如何为tibble中所有数值变量批量计算滞后项?
批量生成滞后变量的函数报错解决方法
问题背景
我编写了一个生成滞后变量的函数mylags,可以为指定变量生成带自定义名称的滞后列并添加到原数据框,单独处理单个变量时功能正常,但用across批量处理所有数值变量时触发错误:
Error in
mutate():
ℹ In argument:across(where(is.numeric), ~mylags(.x, 3)).
Caused by error inacross():
! Can't compute columny.
Caused by error inUseMethod():
! no applicable method for 'mutate' applied to an object of class "c('integer', 'numeric')"
原函数及测试代码如下:
library(dplyr) library(rlang) library(purrr) df <- tibble(x=LETTERS[1:20], y=1:20, z=31:50) mylags <- function(data, variable, n=10){ variable <- enquo(variable) indices <- seq_len(n) quosures <- map( indices, ~quo(lag(!!variable, !!.x)) ) %>% set_names(sprintf("lag_%s_%02d", quo_text(variable), indices)) mutate( data, !!!quosures ) } # 单个变量处理正常 df_lag <- df %>% mylags(y,3) # 批量处理报错 df_lag2 <- df %>% mutate(across(where(is.numeric), ~mylags(.x,3)))
错误原因
across遍历数值列时,.x传入的是单个列的向量(如整数向量),但原mylags函数的第一个参数data期望接收完整数据框,内部调用mutate时会尝试对向量执行数据框操作——而mutate仅支持数据框类对象,因此触发报错。
解决方案
方法一:修改函数适配单个向量处理
重新编写函数,使其接收单个向量并返回包含所有滞后列的tibble,让across可以自动合并结果到原数据框:
mylags_vec <- function(vec, n=10) { indices <- seq_len(n) # 生成滞后列并组合成tibble map_dfc(indices, ~lag(vec, .x)) %>% # 给滞后列命名 set_names(sprintf("lag_%02d", indices)) } # 批量处理,用.names参数添加原变量名前缀 df_lag2 <- df %>% mutate(across(where(is.numeric), ~mylags_vec(.x, n=3), .names = "lag_{col}_{str_pad(.y, 2, pad='0')}"))
方法二:用reduce批量调用原函数
利用purrr::reduce遍历所有数值列名,逐个调用原mylags函数添加滞后列,完全保留原函数的命名逻辑:
# 获取所有数值列的列名 numeric_cols <- df %>% select(where(is.numeric)) %>% colnames() # 逐个处理每个数值列,累积添加滞后列 df_lag2 <- df %>% reduce(numeric_cols, ~mylags(.x, !!sym(.y), n=3), .init = .)
方法三:扩展原函数支持批量变量输入
修改原函数,使其可以接收多个变量(如通过where(is.numeric)筛选),一次性生成所有滞后列:
mylags_multi <- function(data, variables, n=10) { # 解析变量筛选条件,获取变量名 var_names <- data %>% select({{variables}}) %>% colnames() # 遍历每个变量,生成对应的滞后列表达式 lag_quosures <- map(var_names, function(var) { var_sym <- sym(var) indices <- seq_len(n) map(indices, ~quo(lag(!!var_sym, !!.x))) %>% set_names(sprintf("lag_%s_%02d", var, indices)) }) %>% flatten() # 添加所有滞后列到原数据框 mutate(data, !!!lag_quosures) } # 直接处理所有数值列 df_lag2 <- df %>% mylags_multi(variables = where(is.numeric), n=3)
内容的提问来源于stack exchange,提问作者larry77
相关产品推荐
相关产品推荐

