Обучать и тестировать сплиты по уникальным датам, а не наблюдениям, в R - PullRequest
1 голос
/ 08 апреля 2020

Я пытаюсь обучить модель со случайным лесом в 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)

Выглядит примерно так this:

        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 ).

Первое разделение обучения / теста должно быть обучением = 10 первых уникальных дней набора данных, тест = следующие 5 уникальных дней, а затем второе разделение обучения / теста должно быть таким, чтобы набор тестов № 2 был 5 дней сразу после первого набора испытаний.

В отличие от набора данных, который я показал выше, мой набор данных содержит различное количество наблюдений в день. Мой набор данных содержит 417497 наблюдений, но только 2482 уникальных даты, поэтому возможность разделения / обучения на основе «сгруппированных» дат имеет большое значение.

Есть ли какой-нибудь способ, которым я могу использовать trainControl и получить требуемое разделение, или мне придется вручную разделять все мои данные?

1 Ответ

0 голосов
/ 08 апреля 2020

Если я правильно понимаю, ваша цель - создать перекрестную проверку временных рядов блоков с датами в виде блоков.

Один из подходов состоит в том, чтобы использовать 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...