Ric*_*ard 11 r machine-learning r-caret tidyverse
我想使用R包rsample来生成我的数据的重采样.
该软件包提供了rolling_origin生成重采样的功能,以保持数据的时间序列结构.这意味着训练数据(在被调用的包中analysis)总是在测试数据(assessment)的过去.
另一方面,我想执行数据的块样本.这意味着在采样期间将行组保持在一起.这可以使用该功能完成group_vfold_cv.人们可以想到的是几个月.比如说,我们希望时间序列交叉验证始终保持数月.
有没有办法将这两种方法结合起来rsample?
我自己给出每个程序的例子:
## generate some data
library(tidyverse)
library(lubridate)
library(rsample)
my_dates = seq(as.Date("2018/1/1"), as.Date("2018/8/20"), "days")
some_data = data_frame(dates = my_dates)
some_data$values = runif(length(my_dates))
some_data = some_data %>% mutate(month = as.factor(month(dates)))
Run Code Online (Sandbox Code Playgroud)
这给出了以下形式的数据
A tibble: 232 x 3
dates values month
<date> <dbl> <fctr>
1 2018-01-01 0.235 1
2 2018-01-02 0.363 1
3 2018-01-03 0.146 1
4 2018-01-04 0.668 1
5 2018-01-05 0.0995 1
6 2018-01-06 0.163 1
7 2018-01-07 0.0265 1
8 2018-01-08 0.273 1
9 2018-01-09 0.886 1
10 2018-01-10 0.239 1
Run Code Online (Sandbox Code Playgroud)
然后我们可以生成样本,这些样本需要20周的数据并在未来5周内进行测试(参数会skip跳过一些额外的行):
rolling_origin_resamples <- rolling_origin(
some_data,
initial = 7*20,
assess = 7*5,
cumulative = TRUE,
skip = 7
)
Run Code Online (Sandbox Code Playgroud)
我们可以使用以下代码检查数据,看看没有重叠:
rolling_origin_resamples$splits[[1]] %>% analysis %>% tail
# A tibble: 6 x 3
dates values month
<date> <dbl> <fctr>
1 2018-05-15 0.678 5
2 2018-05-16 0.00112 5
3 2018-05-17 0.339 5
4 2018-05-18 0.0864 5
5 2018-05-19 0.918 5
6 2018-05-20 0.317 5
### test data of first split:
rolling_origin_resamples$splits[[1]] %>% assessment
# A tibble: 6 x 3
dates values month
<date> <dbl> <fctr>
1 2018-05-21 0.912 5
2 2018-05-22 0.403 5
3 2018-05-23 0.366 5
4 2018-05-24 0.159 5
5 2018-05-25 0.223 5
6 2018-05-26 0.375 5
Run Code Online (Sandbox Code Playgroud)
或者我们可以分几个月:
## sampling by month:
gcv_resamples = group_vfold_cv(some_data, group = "month", v = 5)
gcv_resamples$splits[[1]] %>% analysis %>% select(month) %>% summary
gcv_resamples$splits[[1]] %>% assessment %>% select(month) %>% summary
Run Code Online (Sandbox Code Playgroud)
正如@missuse解决方案的评论中所讨论的那样,实现这一点的方法记录在github问题中:https://github.com/tidymodels/rsample/issues/42
从本质上讲,我们的想法是首先嵌套在你的"块"上,然后rolling_origin()允许你滚动它们,保持完整的块完好无损.
library(dplyr)
library(lubridate)
library(rsample)
library(tidyr)
library(tibble)
# same data generation as before
my_dates = seq(as.Date("2018/1/1"), as.Date("2018/8/20"), "days")
some_data = data_frame(dates = my_dates)
some_data$values = runif(length(my_dates))
some_data = some_data %>% mutate(month = as.factor(month(dates)))
# nest by month, then resample
rset <- some_data %>%
group_by(month) %>%
nest() %>%
rolling_origin(initial = 1)
# doesn't show which month is which :(
rset
#> # Rolling origin forecast resampling
#> # A tibble: 7 x 2
#> splits id
#> <list> <chr>
#> 1 <S3: rsplit> Slice1
#> 2 <S3: rsplit> Slice2
#> 3 <S3: rsplit> Slice3
#> 4 <S3: rsplit> Slice4
#> 5 <S3: rsplit> Slice5
#> 6 <S3: rsplit> Slice6
#> 7 <S3: rsplit> Slice7
# only January (31 days)
analysis(rset$splits[[1]])$data
#> [[1]]
#> # A tibble: 31 x 2
#> dates values
#> <date> <dbl>
#> 1 2018-01-01 0.373
#> 2 2018-01-02 0.0389
#> 3 2018-01-03 0.260
#> 4 2018-01-04 0.803
#> 5 2018-01-05 0.595
#> 6 2018-01-06 0.875
#> 7 2018-01-07 0.273
#> 8 2018-01-08 0.180
#> 9 2018-01-09 0.662
#> 10 2018-01-10 0.849
#> # ... with 21 more rows
# only February (28 days)
assessment(rset$splits[[1]])$data
#> [[1]]
#> # A tibble: 28 x 2
#> dates values
#> <date> <dbl>
#> 1 2018-02-01 0.402
#> 2 2018-02-02 0.556
#> 3 2018-02-03 0.764
#> 4 2018-02-04 0.134
#> 5 2018-02-05 0.0333
#> 6 2018-02-06 0.907
#> 7 2018-02-07 0.814
#> 8 2018-02-08 0.0973
#> 9 2018-02-09 0.353
#> 10 2018-02-10 0.407
#> # ... with 18 more rows
Run Code Online (Sandbox Code Playgroud)
由reprex包(v0.2.0)于2018-08-28创建.
这也可以通过 来完成tidyroll,它是一个小型 R 包,其中包含一系列方便的函数,用于处理具有不规则时间片的时间序列数据。
rolling_origin_nested是一个包装器rolling_origin,具有许多不错的功能,包括允许用户选择滚动的单位(分钟、天、周、月等)、开始和结束日期/时间以及是否暂时滚动扩展数据,以便start和之间的所有观测值end都被预测assess次数。
# devtools::install_github("gacolitti/tidyroll")
library(tidyverse)
library(lubridate)
library(rsample)
library(tidyroll)
my_dates = seq(as.Date("2018/1/1"), as.Date("2018/8/20"), "days")
some_data = data.frame(dates = my_dates)
some_data$values = runif(length(my_dates))
roll <- rolling_origin_nested(some_data,
time_var = "dates",
unit = "month",
start = "2018-01-01")
roll
#> # Rolling origin forecast resampling
#> # A tibble: 7 x 2
#> splits id
#> <list> <chr>
#> 1 <split [1/1]> Slice1
#> 2 <split [2/1]> Slice2
#> 3 <split [3/1]> Slice3
#> 4 <split [4/1]> Slice4
#> 5 <split [5/1]> Slice5
#> 6 <split [6/1]> Slice6
#> 7 <split [7/1]> Slice7
analysis(roll$splits[[1]])$data[[1]] %>% tail
#> # A tibble: 6 x 2
#> dates values
#> <dttm> <dbl>
#> 1 2018-01-26 00:00:00 0.0929
#> 2 2018-01-27 00:00:00 0.536
#> 3 2018-01-28 00:00:00 0.194
#> 4 2018-01-29 00:00:00 0.600
#> 5 2018-01-30 00:00:00 0.449
#> 6 2018-01-31 00:00:00 0.754
assessment(roll$splits[[1]])$data[[1]] %>% head
#> # A tibble: 6 x 2
#> dates values
#> <dttm> <dbl>
#> 1 2018-02-01 00:00:00 0.945
#> 2 2018-02-02 00:00:00 0.733
#> 3 2018-02-03 00:00:00 0.626
#> 4 2018-02-04 00:00:00 0.585
#> 5 2018-02-05 00:00:00 0.303
#> 6 2018-02-06 00:00:00 0.767
Run Code Online (Sandbox Code Playgroud)
还有一些其他方便的功能,例如fit_rsample_nested和 ,predict_rsample_nested它们有助于处理使用 创建的对象rolling_origin_nested和使用 进行数据预处理recipes。
一项非常酷的功能predict_rsample_nested是能够通过额外的recipe步骤来估算预测变量值,而这些值可能不可用,具体取决于预测日期。