Объедините nesting и Rolling_origin из Tidymodels в R

Я пытаюсь обучить случайный лес с помощью Rolling_origin из набора Tidymodels. Хотелось бы, чтобы складки были именно по месяцам года. Вложенность выглядит так, как будто это может помочь, но tune_grid не может найти переменные, когда данные вложены. Как я могу заставить это работать? Ниже я привел воспроизводимый пример.


suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(tidymodels))
suppressPackageStartupMessages(library(yardstick))

# Create dummy data ====================================================================================================

dates <- seq(from = as.Date("2019-01-01"), to = as.Date("2019-12-31"), by = 'day' )
l <- length(dates)

set.seed(1)
data_set <- data.frame(
  date = dates,
  v1 = rnorm(l),
  v2 = rnorm(l),
  v3 = rnorm(l),
  y = rnorm(l)
)

# Random Forest Model  =================================================================================================

model <-
  parsnip::rand_forest(
    mode = "regression",
    trees = tune()) %>%
  set_engine("ranger")

# grid specification
params <-
  dials::parameters(
    trees()
  )

# Set up grid and model workflow =======================================================================================

grid <-
  dials::grid_max_entropy(
    params,
    size = 2
  )

form <- as.formula(paste("y ~ v1 + v2 + v3"))

model_workflow <-
  workflows::workflow() %>%
  add_model(model) %>%
  add_formula(form)

# Tuning on the normal data set works ====================================================================================================

data_ro_day <- data_set %>%
  rolling_origin(
    initial = 304,
    assess = 30,
    cumulative = TRUE,
    skip = 30
  )

results <- tune_grid(
  model_workflow,
  grid = grid,
  resamples = data_ro_day,
  param_info = params,
  metrics   = metric_set(mae, mape, rmse, rsq),
  control   = control_grid(verbose = TRUE))

results %>% show_best("mape", n = 2)

# Tuning on the nested data set doesn't work =========================================================================================

data_ro_month <- data_set %>%
  mutate(year_month = format(date, "%Y-%m")) %>%
  nest(-year_month) %>%
  rolling_origin(
    initial = 10,
    assess = 1,
    cumulative = TRUE
  )

results <- tune_grid(
    model_workflow,
    grid = grid,
    resamples = data_ro_month,
    param_info = params,
    metrics   = metric_set(mae, mape, rmse, rsq),
    control   = control_grid(verbose = TRUE))

results$.notes ```

person ThePhil    schedule 13.11.2020    source источник


Ответы (1)


Я не совсем понимаю, как вы хотите разделить данные для настройки, но я бы рекомендовал изучить некоторые другие функции rsample, такие как sliding_window() и особенно sliding_period(). Они позволяют вам создавать экспериментальные проекты для настройки, где вы можете соответствовать данным за определенные месяцы, а затем оценивать данные за другой месяц, перемещаясь по всем месяцам, которые у вас есть:

library(tidymodels)
dates <- seq(from = as.Date("2019-01-01"), to = as.Date("2019-12-31"), by = 'day' )
l <- length(dates)

set.seed(1)
data_set <- tibble(
  date = dates,
  v1 = rnorm(l),
  v2 = rnorm(l),
  v3 = rnorm(l),
  y = rnorm(l)
)

month_folds <- data_set %>%
  sliding_period(
    date,
    "month",
    lookback = Inf,
    skip = 4
  )

month_folds
#> # Sliding period resampling 
#> # A tibble: 7 x 2
#>   splits           id    
#>   <list>           <chr> 
#> 1 <split [151/30]> Slice1
#> 2 <split [181/31]> Slice2
#> 3 <split [212/31]> Slice3
#> 4 <split [243/30]> Slice4
#> 5 <split [273/31]> Slice5
#> 6 <split [304/30]> Slice6
#> 7 <split [334/31]> Slice7

Я использовал skip = 4 здесь, чтобы сохранить только те фрагменты, где у вас будет больше данных для обучения. Каждый из этих фрагментов будет обучаться на данных за несколько месяцев и оценивать на новом, прошлом месяце. Повторные выборки продвигаются по вашему набору данных. Поскольку я использовал lookback = Inf, он всегда включает все прошлые данные, но вы можете это изменить.

Когда у вас настроен подход передискретизации, который подходит для вашей предметной проблемы, вы можете создать спецификацию модели и настроить ее:

rf_spec <-
  rand_forest(
    mode = "regression",
    trees = tune()) %>%
  set_engine("ranger")

rf_wf <-
  workflow() %>%
  add_model(rf_spec) %>%
  add_formula(y ~ v1 + v2 + v3)

tune_grid(rf_wf, resamples = month_folds)
#> # Tuning results
#> # Sliding period resampling 
#> # A tibble: 7 x 4
#>   splits           id     .metrics          .notes          
#>   <list>           <chr>  <list>            <list>          
#> 1 <split [151/30]> Slice1 <tibble [20 × 5]> <tibble [0 × 1]>
#> 2 <split [181/31]> Slice2 <tibble [20 × 5]> <tibble [0 × 1]>
#> 3 <split [212/31]> Slice3 <tibble [20 × 5]> <tibble [0 × 1]>
#> 4 <split [243/30]> Slice4 <tibble [20 × 5]> <tibble [0 × 1]>
#> 5 <split [273/31]> Slice5 <tibble [20 × 5]> <tibble [0 × 1]>
#> 6 <split [304/30]> Slice6 <tibble [20 × 5]> <tibble [0 × 1]>
#> 7 <split [334/31]> Slice7 <tibble [20 × 5]> <tibble [0 × 1]>

Создано 15.11.2020 с помощью пакета REPEX (v0.3.0.9001)

person Julia Silge    schedule 15.11.2020
comment
Спасибо, Джулия, я не знала о slide_period, это хорошо работает! - person ThePhil; 19.11.2020