使用mutate(across(all_of()))结合cur_column()出现递归错误
问题解决:在dplyr的across中动态引用对应后缀列
核心问题分析
你遇到的递归错误和列引用偏差,本质是在across()的lambda表达式中,使用!!sym()进行tidyeval的时机不匹配,结合嵌套数据框的环境特性,导致无法正确解析动态生成的列名。硬编码列名能运行但复用性差,而cur_column()需要配合正确的列索引方式来获取对应的_OVERRIDE列。
修正后的代码
方法1:使用.data代词动态索引(推荐)
.data是dplyr中的特殊代词,能安全访问当前数据框的列,结合cur_column()可以动态拼接列名:
library(dplyr) # 定义趋势函数 TREND_LOSS <- function(LOSSES, YEARS, OVERRIDES) { x <- YEARS y <- log(LOSSES) xy <- x * y x_sq <- x * x sum_x <- sum(x) sum_y <- sum(y) sum_xy <- sum(xy) sum_x_sq <- sum(x_sq) n <- length(YEARS) Slope <- (n*sum_xy - sum_x*sum_y) / (n*sum_x_sq - sum_x*sum_x) OVERRIDES[is.na(OVERRIDES)] <- Slope TRENDED_LOSSES <- LOSSES * exp(OVERRIDES) return(TRENDED_LOSSES) } # 构造数据 LR_DATA <- data.frame(STATE = c(1,2,3), YEAR = c(2000,2001,2002), DEVT_A = c(2,4,6), DEVT_B = c(3,6,9), DEVT_C = c(4,8,12)) LOSS_COLS <- c("DEVT_A", "DEVT_B", "DEVT_C") DATA_OVERRIDE <- data.frame(STATE = c(1,2,3), DEVT_A_OVERRIDE = c(NaN,1,1), DEVT_B_OVERRIDE = c(1,1,1), DEVT_C_OVERRIDE = c(1.5,1.5,1.5)) LR_DATA <- LR_DATA %>% left_join(DATA_OVERRIDE, by = 'STATE') # 修正后的处理流程 TRENDED_LR_DATA <- LR_DATA %>% summarise(across(everything(), list), .groups = "keep") %>% mutate(across(all_of(LOSS_COLS), ~list(TREND_LOSS(unlist(.x), unlist(YEAR), unlist(.data[[paste0(cur_column(), "_OVERRIDE")]])))))
方法2:使用cur_column()结合get()函数
如果习惯用基础R的索引方式,也可以用get()在当前环境中获取列:
TRENDED_LR_DATA <- LR_DATA %>% summarise(across(everything(), list), .groups = "keep") %>% mutate(across(all_of(LOSS_COLS), ~list(TREND_LOSS(unlist(.x), unlist(YEAR), unlist(get(paste0(cur_column(), "_OVERRIDE"), envir = cur_data()))))))
关键修正点说明
- 替换
!!sym()为.data[[...]]:在across()的lambda中,.data能直接指向当前数据框,动态拼接的列名通过[[ ]]索引,避免了tidyeval的时机冲突,解决递归错误。 cur_column()的正确使用:cur_column()在across()内部会返回当前正在处理的列名,配合paste0()生成对应的_OVERRIDE列名,确保每个损失列都匹配到专属的覆盖列。- 嵌套数据的
unlist()处理:因为summarise(across(everything(), list))把所有列转成了嵌套列表,所以必须用unlist()把向量从列表中提取出来,才能传入TREND_LOSS函数计算。
验证结果
运行修正后的代码,每个DEVT_*列都会使用对应的DEVT_*_OVERRIDE列数据:
- DEVT_A会用DEVT_A_OVERRIDE(NaN被替换为计算的Slope)
- DEVT_B用DEVT_B_OVERRIDE
- DEVT_C用DEVT_C_OVERRIDE
内容的提问来源于stack exchange,提问作者moo5003
相关产品推荐
相关产品推荐

