我正在尝试使用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 Class1 2009-01-01 Stock A 52 2009-01-01 Stock B 23 2009-01-01 Stock C 44 2009-01-01 Stock D 105 2009-01-01 Stock E 76 2009-01-01 Stock F 3...11 2009-01-02 Stock A 1012 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)。
第一个训练/测试分割应该是训练集为数据集的前10个唯一日期,测试集为接下来的5个唯一日期,然后第二个训练/测试分割应该是测试集2紧跟在第一个测试集之后的5天。
与我上面展示的数据集不同,我的实际数据集每天包含不同数量的观测值。我的数据集包含417497个观测值,但只有2482个唯一日期,因此能够基于“分组”的日期进行训练/测试分割会产生很大差异。
有没有什么方法可以使用trainControl来获得我需要的分割,还是我必须手动分割所有数据?
回答:
如果我理解正确的话,你的目标是创建以日期为块的块时间序列交叉验证。
一种方法是使用createTimeSlices
在唯一日期(按顺序)上,然后将这些分割映射回你的数据集:
dates <- unique(DF$Date) #already in orderslices <- 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)