You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R tsibble构建组合预测时mable转tibble无法调用forecast问题

问题描述

我正在跟随Rob Hyndman博士的R语言时间序列预测教材学习,当前学到第13章“实用预测问题”的组合预测小节,实操时遇到如下问题:
构建组合预测模型时,对已训练模型做线性组合计算的代码会把原本的mable对象强制转换成普通tibble对象;如果移除组合计算的代码行,model()函数会正常返回mable对象,且无法将得到的tibble重新转回mable类型。

教材参考代码

auscafe <- aus_retail %>%
  filter(stringr::str_detect(Industry, "Takeaway")) %>%
  summarise(Turnover = sum(Turnover))

train <- auscafe %>%
  filter(year(Month) <= 2013)

STLF <- decomposition_model(
  STL(log(Turnover) ~ season(window = Inf)),
  ETS(season_adjust ~ season("N"))
)

cafe_models <- train %>%
  model(
    ets = ETS(Turnover),
    stlf = STLF,
    arima = ARIMA(log(Turnover))
  ) %>%
  mutate(combination = (ets + stlf + arima) / 3)

cafe_fc <- cafe_models %>% 
forecast(h = "5 years")

本地运行同类代码无法得到预期结果,教材示例所用数据集存放在fable、fabletools、feasts、tsibble、tsibbledata其中一个包中。

个人测试数据结构

structure(list(Date = structure(c(19114, 19115, 19116, 19117, 
19118, 19119, 19120, 19121, 19122, 19123, 19124, 19125, 19126, 
19127, 19128, 19129, 19130, 19131, 19132, 19133, 19134, 19135, 
19136, 19137, 19138, 19139, 19140, 19141, 19142, 19143, 19144, 
19145, 19146, 19147, 19148, 19149, 19150, 19151, 19152, 19153, 
19154, 19155, 19156, 19157, 19158, 19159, 19160, 19161, 19162, 
19163, 19164, 19165), class = "Date"), Sales = c(2147350, 1953453, 
1930514, 1951737, 2496552, 2091370, 1921364, 2342280, 2224779, 
2124766, 2229922, 2501654, 2056751, 1908814, 2109249, 1946929, 
2057711, 2001398, 2535514, 2060774, 1793765, 1954603, 2019082, 
2077929, 2152838, 2802181, 2314866, 2268680, 2380746, 1887751, 
2201204, 2004422, 2783170, 2238542, 2000024, 1777258, 1844045, 
2138638, 2387784, 2783170, 1988945, 1749007, 2128774, 2101340, 
2122877, 2085712, 2532569, 1995143, 1713529, 2045398, 1781901, 
2164901)), class = c("tbl_ts", "tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-52L), key = structure(list(.rows = structure(list(1:52), ptype = integer(0), class = c("vctrs_list_of", 
"vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -1L)), index = structure("Date", ordered = TRUE), index2 = "Date", interval = structure(list(
    year = 0, quarter = 0, month = 0, week = 0, day = 1, hour = 0, 
    minute = 0, second = 0, millisecond = 0, microsecond = 0, 
    nanosecond = 0, unit = 0), .regular = TRUE, class = c("interval", 
"vctrs_rcrd", "vctrs_vctr")))

个人编写代码

library(tsibble)
library(tsibbledata)
library(fable)
library(fabletools)
library(feasts)

my_dcmp_spec <- decomposition_model(
  STL(Sales),
  ETS(season_adjust ~ season("N"))
)

fit <- time_series_sample %>%
  model(
    stl_ets = my_dcmp_spec,
    `Seasonal naïve` = SNAIVE(Sales),
    holt_winters = ETS(Sales ~ error("A") + trend("N") + season("N"))
  ) %>%
    mutate(combination = (stl_ets + `Seasonal naïve` + holt_winters) / 3) 

运行预测步骤代码时报错:

fc <- fit %>% forecast(h = 21)

报错信息:

Error in UseMethod("forecast") : 
  no applicable method for 'forecast' applied to an object of class "c('tbl_df', 'tbl', 'data.frame')"

尝试用as_mable()强制转换类型时也报错:

fit %>% as_mable()

报错信息:

Error in `build_mable()`:
! A mable must contain at least one model.
Backtrace:
 1. fit %>% as_mable()
 3. fabletools:::as_mable.data.frame(.)
 4. fabletools:::build_mable(x, key = !!enquo(key), model = !!enquo(model))

实际tibble中确实包含模型对象,对应单元格存储的是S3类型lst_model对象,尝试结合pivot_longer()与as_mable()转换也无法解决问题。只要代码中包含mutate()生成组合模型的步骤,最终得到的就是普通tibble而非mable。

移除组合模型生成步骤时可以正常运行预测和绘图:

fit <- time_series_sample %>%
  model(
    stl_ets = my_dcmp_spec,
    seasonal_naive = SNAIVE(Sales),
    holt_winters = ETS(Sales ~ error("A") + trend("N") + season("N"))
  ) 

fc <- fit %>% forecast(h = 21)

fc %>% autoplot(time_series_sample) 

但该结果缺少需要的组合预测输出,不确定是否为包的bug:mutate步骤确实成功生成了模型的线性组合(单元格为lst_model类型),但mable被转为tibble后无法调用forecast方法完成预测。


解决方案

这个问题是旧版本fabletools包的已知bug,mutate()新增组合模型列时没有正确保留mable类属性,导致后续方法调用失败,修复方法如下:

  • 先把fable相关的包全部更新到CRAN最新版本,直接在控制台运行更新命令即可:
    install.packages(c("fable", "fabletools", "tsibble", "feasts", "tsibbledata"))
    
  • 更新完成后重启R会话,重新运行原有代码,mutate()新增组合模型后会正常保留mable类型,可直接调用forecast()方法,不需要额外做类型转换。
  • 如果暂时无法更新包,可以用临时绕过方案:不要在model()后链式调用mutate()加组合模型,而是把组合模型直接写在model()函数的参数里,这样从一开始就会正确生成mable对象:
    fit <- time_series_sample %>%
      model(
        stl_ets = my_dcmp_spec,
        `Seasonal naïve` = SNAIVE(Sales),
        holt_winters = ETS(Sales ~ error("A") + trend("N") + season("N")),
        combination = (stl_ets + `Seasonal naïve` + holt_winters) / 3
      )
    
    注意这个写法要求所有被组合的模型都在同一个model()调用里定义,顺序不能错,组合列要放在被引用的模型列后面。

不要尝试手动用as_mable()转换被转成tibble的对象,旧版本中这个方法无法自动识别新增的模型列,手动指定模型列参数的写法非常繁琐,远不如上面两种方案高效。


内容的提问来源于stack exchange,提问作者hachiko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:54:09