Как использовать символьное значение при использовании функции «модель» для вызова модели/переменной для прогнозирования?

#r #time-series #character #forecasting #tsibble

Вопрос:

Моя цель состоит в том, чтобы создать функцию, в которой вы вводите переменную, которую хотите спрогнозировать, а затем используете перекрестную проверку для нескольких типов моделей (т. Е. Наивный, ETS, Средний), затем, используя функцию «вытянуть», я вытащу модель с наименьшим RMSE, а затем спрогнозирую на 1 шаг вперед с лучшей моделью.

Тем не менее, у меня возникли проблемы со второй последней строкой, используя значение символа «best.model» в качестве входных данных для модели при прогнозировании. (Ошибка находится ниже кода, который вы можете запустить самостоятельно).

Вот код, чтобы было больше смысла:

 library(fpp3)
tsibble <- prices

function.fc <- function (variable) {

## cross validation models
cv.fit <- tsibble %>%
  select(year, !!sym(variable)) %>%
  stretch_tsibble(.init = 180, .step = 1) %>%
  filter(.id != max(.id)) %>%
  model(
    MEAN(!!sym(variable)),
    NAIVE(!!sym(variable))
  ) 

## cv forecasts
cv.fc <- cv.fit %>%
  forecast(h = 1)

## cv accuracy
cv.accuracy <- cv.fc %>%
  accuracy(tsibble)

## pulls out the name of the best model
best.model <- cv.accuracy %>%
  select(.model, .type, RMSE) %>%
  arrange(RMSE) %>%
  filter(row_number(RMSE) == 1) %>%
  pull(.model)

## pulls out 1 step forecast 
fc <- model(.data = tsibble, noquote(best.model)) %>%
  forecast(h = 1)


return(fc)

}


function.fc("copper")

Error: Model definition(s) incorrectly created: noquote(best.model) Check that specified model(s) are model definitions. Run `rlang::last_error()` to see where the error occurred
 

Как вы можете видеть, я пытался использовать функцию «снять кавычки», но это все равно не работает.
У кого-нибудь есть какие-либо предложения о том, что использовать? Я изо всех сил пытался найти другие сообщения с моей проблемой.

Ответ №1:

В конце вашей функции best.model находится строка. Например, если variable = "copper" , то ваша функция производит best.model = "NAIVE(copper)" . model() Функция требует, чтобы было предоставлено определение модели, а не строки. Вы можете проанализировать строку как код, используя rlang::parse_expr() затем оценить ее для создания определения модели rlang::eval_tidy() .

 library(rlang)
library(fpp3)
#> ── Attaching packages ──────────────────────────────────────────── fpp3 0.4.0 ──
#> ✓ tibble      3.1.0          ✓ tsibble     1.0.0     
#> ✓ dplyr       1.0.5          ✓ tsibbledata 0.3.0     
#> ✓ tidyr       1.1.3          ✓ feasts      0.2.1.9000
#> ✓ lubridate   1.7.10         ✓ fable       0.3.0.9000
#> ✓ ggplot2     3.3.3
best.model <- "NAIVE(copper)"
best.model <- eval_tidy(parse_expr(best.model))
best.model
#> <RW model definition>
model(prices, best.model)
#> # A mable: 1 x 1
#>   best.model
#>      <model>
#> 1    <NAIVE>
 

Создано 2021-05-11 пакетом reprex (v1.0.0)

Комментарии:

1. Это отлично сработало, Митч ура. Я не удивлен, что лучший туте 3550 нашел бы решение!

Ответ №2:

Вот решение, которое использует несколько иной подход, сначала определяя именованный список моделей на выбор, а затем используя best.model для выбора из списка. Это, как правило, предпочтительнее, чем увязнуть в нестандартной оценке. Обратите также внимание, что я использовал для передачи аргументов без кавычек. {{ Вы заметите, что я также изменил некоторые имена объектов. Это связано с тем, что обычно следует избегать . имен объектов, чтобы избежать путаницы с S3 системой объектно-ориентированного программирования в R.

 library(fpp3)

my_forecast <- function(data, variable) {
  
  # Define a list of models with sensible names
  models <- list(
    mean = fable::MEAN,
    naive = fable::NAIVE
  )
  
  ## cross validation models
  cv_fit <- data %>%
    select(year, {{ variable }}) %>%
    stretch_tsibble(.init = 180, .step = 1) %>%
    filter(.id != max(.id)) %>%
    model(
      mean = models$mean({{ variable }}),
      naive = models$naive({{ variable }})
    ) 
  
  ## cv forecasts
  cv_fc <- cv_fit %>%
    forecast(h = 1)
  
  ## cv accuracy
  cv_accuracy <- cv_fc %>%
    accuracy(data)
  
  ## pulls out the name of the best model
  best_model <- cv_accuracy %>%
    select(.model, .type, RMSE) %>%
    arrange(RMSE) %>%
    filter(row_number() == 1) %>%
    pull(.model)
  
  ## pulls out 1 step forecast 
  fc <- data %>% 
    model("{best_model}" := models[[best_model]]({{ variable }})) %>%
    forecast(h = 1)
  
  fc
  
}

my_forecast(prices, copper)
#> # A fable: 1 x 4 [1Y]
#> # Key:     .model [1]
#>   .model  year       copper .mean
#>   <chr>  <dbl>       <dist> <dbl>
#> 1 naive   1998 N(2.6, 0.69)  2.59
 

Создано 2021-05-11 пакетом reprex (v2.0.0)