如何用Tidy/Fable范式从数据框选多外生回归变量适配ARIMA模型?
在Tidy/tidyverts/Fable范式下为ARIMA模型选择多个外生回归变量
问题描述
Q:使用Tidy/tidyverts/Fable范式,如何从数据框中选择多个外生回归变量用于模型拟合,尤其是适配
ARIMA()?我搭建了一个最小可复现示例,多次尝试都失败了,显然我对
rlang中的解引用、符号化、注入、拼接这些概念还没搞懂。不过最后找到了一种符合Tidy范式的方法:dat %>% model(arima=ARIMA(y~xreg(!!!xreg.syms)))。就算这个方法能用,我也想知道它为什么有效,而其他尝试都失败了?
最小可复现代码
library(dplyr) library(purrr) library(tsibble) library(fable) library(fabletools) set.seed(123) tibble( idx=1:12, y=rnorm(12), x1=c(0,0,1,rep(0,9)), x2=c(rep(0,9),1,0,0)) %>% tsibble(index=idx) -> dat # # A tsibble: 12 x 4 [1] # idx y x1 x2 # <int> <dbl> <dbl> <dbl> # 1 1 -0.560 0 0 # 2 2 -0.230 0 0 # 3 3 1.56 1 0 # 4 4 0.0705 0 0 # 5 5 0.129 0 0 # 6 6 1.72 0 0 # 7 7 0.461 0 0 # 8 8 -1.27 0 0 # 9 9 -0.687 0 0 # 10 10 -0.446 0 1 # 11 11 1.22 0 0 # 12 12 0.360 0 0 # 手动指定变量,可行但麻烦 dat %>% model(arima=ARIMA(y~x1+x2)) # SUCCESS # 错误用法:用:表示变量选择 dat %>% model(arima=ARIMA(y~x1:x2)) # FAILURE # 用xreg()手动指定,可行但同样麻烦 dat %>% model(arima=ARIMA(y~xreg(x1,x2))) # SUCCESS # 尝试传入字符向量,失败 dat %>% as_tibble() %>% select(-idx, -y) %>% colnames() -> xreg.ch dat %>% model(arima=ARIMA(y~xreg(xreg.ch))) # FAILURE # 尝试传入列表,失败 dat %>% as_tibble() %>% select(-idx, -y) %>% colnames() %>% as.list() -> xreg.ls dat %>% model(arima=ARIMA(y~xreg(xreg.ls))) # FAILURE # 尝试传入数据框,失败 dat %>% as_tibble() %>% select(-idx, -y) -> xreg.df dat %>% model(arima=ARIMA(y~xreg(xreg.df))) # FAILURE # 字符向量直接用!!!拼接,失败 dat %>% model(arima=ARIMA(y~xreg(!!!xreg.ch))) # FAILURE # 错误提示:ARIMA(y ~ xreg("x1", "x2")) [1] invalid model formula in ExtractVars # 尝试用vars(),失败 dat %>% model(arima=ARIMA(y~xreg(vars(x1,x2)))) # FAIL # 传入矩阵,可行但不够优雅 dat %>% as_tibble() %>% select(-idx, -y) %>% as.matrix() -> xreg.mat dat %>% model(arima=ARIMA(y~xreg(xreg.mat))) -> fit # SUCCESS!! fit %>% pull(arima) %>% pluck(1, 'fit', 'par') # # A tibble: 2 × 5 # term estimate std.error statistic p.value # <chr> <dbl> <dbl> <dbl> <dbl> # 1 xreg.matx1 -0.491 0.821 -0.598 0.561 # 2 xreg.matx2 -0.0713 0.821 -0.0869 0.932 # 符号向量+!!!拼接,可行且符合Tidy范式 dat %>% as_tibble() %>% select(-idx, -y) %>% colnames() %>% syms() -> xreg.syms dat %>% model(arima=ARIMA(y~xreg(!!!xreg.syms))) -> fit # SUCCESS!!?? fit %>% pull(arima) %>% pluck(1, 'fit', 'par') # # A tibble: 2 × 5 # term estimate std.error statistic p.value # <chr> <dbl> <dbl> <dbl> <dbl> # 1 x1 -0.491 0.821 -0.598 0.561 # 2 x2 -0.0713 0.821 -0.0869 0.932
解答
更简洁的Tidy风格写法
除了你找到的方法,还可以直接用tidyselect语法配合pick()函数,不需要手动转换符号,更符合Tidy范式:
# 选择所有以x开头的变量 dat %>% model(arima = ARIMA(y ~ xreg(pick(starts_with("x"))))) # 排除idx和y,选择剩余变量 dat %>% model(arima = ARIMA(y ~ xreg(pick(-idx, -y))))
为什么xreg(!!!xreg.syms)有效?
核心在于rlang的符号处理和拼接机制:
syms(xreg.ch)把字符串向量c("x1","x2")转换成符号对象——符号是R用来代表变量名的语法元素,和你手动写x1本质一样。!!!是rlang的拼接运算符,它会把符号向量拆成单独的参数传递给xreg(),也就是xreg(!!!xreg.syms)等价于xreg(x1, x2),这正是ARIMA()能识别的格式。
其他尝试失败的原因
逐个拆解:
y~x1:x2::在公式里表示交互项,不是选择多个变量,模型会尝试拟合x1和x2的交互效应,而非把它们作为独立外生变量,自然报错。xreg(xreg.ch)/xreg(xreg.ls):xreg()需要接收变量名(符号),而不是字符串向量或列表,R会把这些对象当成单个变量名去查找,数据里没有对应变量,直接失败。xreg(xreg.df):数据框会被当成单个输入对象,模型无法解析其中的列作为独立变量,而矩阵能成功是因为xreg()支持矩阵输入,但会丢失原变量名,不够优雅。xreg(!!!xreg.ch):字符串直接用!!!拼接会变成xreg("x1","x2"),模型把字符串当成字面量,而非变量名,无法解析。xreg(vars(x1,x2)):vars()是tidyverse的变量选择工具,但xreg()不兼容这个语法,无法识别其返回的对象。
内容的提问来源于stack exchange,提问作者lowndrul
相关产品推荐
相关产品推荐

