在 R 中按唯一日期而不是观察进行训练和测试拆分

Train and test splits by unique dates, not observations, in R

我正在尝试用 R 中的随机森林训练一个模型。我有一个时间序列,其中包含每个日期多个股票的信息,并创建了一个非常简化的版本:

Date <- rep(seq(as.Date("2009/01/01"), by = "day", length.out = 100), 10)
Name <- c(rep("Stock A", 100), rep("Stock B",100), rep("Stock C", 100), rep("Stock D", 100), rep("Stock E",100), rep("Stock F",100), rep("Stock G",100), rep("Stock H",100), rep("Stock I", 100), rep("Stock J", 100))
Class <- sample(1:10, 1000, replace=TRUE)

DF <- data.frame(Date, Name, Class)
DF <- DF %>% arrange(Date, Name)

看起来像这样:

        Date   Name    Class
1  2009-01-01  Stock A     5
2  2009-01-01  Stock B     2
3  2009-01-01  Stock C     4
4  2009-01-01  Stock D    10
5  2009-01-01  Stock E     7
6  2009-01-01  Stock F     3
...
11 2009-01-02  Stock A    10
12 2009-01-02  Stock B     8 
13 2009-01-02  Stock C     9

当使用 trainControl 将数据拆分为训练和测试周期时,拆分是根据每次观察完成的,但我希望根据在独特的日子里。到目前为止我所做的是:

timecontrol <- DF %>% group_by(Date) %>% trainControl(
  method            = 'timeslice',
  initialWindow     = 10,
  horizon           = 5,
  skip              = 4,
  fixedWindow       = TRUE,
  returnData        = TRUE, 
  classProbs        = TRUE
)

fitRF <- train(Class ~ ., 
               data = DF,
               method = "ranger",
               tuneGrid = tunegrid,
               na.action = na.omit,
               trControl = timecontrol)

这为我提供了一个包含 10 个观察值的训练集,然后是 5 个测试观察值。 但是,我希望有一个训练集(和测试..)包含 10 个不同日期的所有观察结果,这样一个训练集将是 10 天乘以每天的观察次数,并且在期间之间有一个跳跃,以便每个测试期都是基于全新的数据(因此 skip=4)。

第一个 training/test 拆分应该是训练 = 数据集的第一个唯一天数,测试 = 接下来的 5 个唯一天数,然后第二个 training/test 拆分应该是测试集编号 2是第一次测试集后的 5 天。

与我上面显示的数据集不同,我的数据集每天包含不同数量的观察结果。我的数据集包含 417497 个观测值,但只有 2482 个唯一日期,因此能够根据 "grouped" 日期进行 training/testing 拆分会产生很大的不同。

有什么方法可以使用 trainControl 并获得我需要的拆分,还是我必须手动拆分所有数据?

如果我理解正确的话,您的目标是创建以日期为块的块时间序列交叉验证。

一种方法是对唯一日期(按顺序)使用 createTimeSlices,然后将其映射回您的数据集:

dates <- unique(DF$Date) #already in order


slices <- createTimeSlices(dates,
                           initialWindow = 10,
                           horizon = 5,
                           skip = 4,
                           fixedWindow = TRUE)

将这些切片映射回原始数据中的索引:

slices <- lapply(slices, function(x){
  lapply(x, function(k){
    DF %>%
      mutate(n = 1:n()) %>%
      filter(Date %in% dates[k]) %>%
      pull(n)
  })
})

所以第一个训练数据帧将是:

DF[slices$train[[1]],]

而测试数据将是:

DF[slices$test[[1]],]

现在在定义 trainControl 时使用获得的训练和测试索引:

tr <- trainControl(returnData = TRUE, 
                   classProbs = TRUE,
                   index = slices$train,
                   indexOut = slices$test)

数据:

Date <- rep(seq(as.Date("2009/01/01"), by = "day", length.out = 100), 10)
Name <- c(rep("Stock A", 100), rep("Stock B",100), rep("Stock C", 100), rep("Stock D", 100), rep("Stock E",100), rep("Stock F",100), rep("Stock G",100), rep("Stock H",100), rep("Stock I", 100), rep("Stock J", 100))
Class <- sample(1:10, 1000, replace=TRUE)

DF <- data.frame(Date, Name, Class)
DF <- DF %>% arrange(Date, Name)