使用summarise/across结合lm拟合回归时输出丢失原列名的问题咨询
问题根源
常规写法中across传入匿名函数的.x是当前列的数值向量,而非携带原始列名的符号引用。dplyr的across设计上不会向匿名函数传递列的符号对象,因此cur_column()是官方提供的、在across执行流程中获取当前处理列名的标准渠道。
而lm解析公式时,会根据传入的符号名生成回归项的名称,由于.x是无附加列名的向量,lm无法获知其原始列名,因此自动为这个回归项分配默认名称.x,最终导致输出结果的项名错误。
优雅实现方案
所有方案均保持summarise+across的原生范式,不引入map类函数,无繁琐字符串拼接逻辑。
方案1:后置修正项名(完全保留原始回归公式)
该方案完全沿用最初编写的回归公式,仅在tidy输出后对自动生成的.x项名做一次替换,逻辑最清晰、改动最小:
library(tidyverse) library(broom) fits <- tibble(mtcars) %>% summarise(across(c(vs, am), ~list({ # 原有回归公式完全不改动 model_tidy <- tidy(lm(wt ~ .x + mpg)) # 替换默认生成的.x为真实列名 model_tidy$term[model_tidy$term == ".x"] <- cur_column() model_tidy })))
运行验证:
fits %>% unnest(vs) # A tibble: 3 x 6 term estimate std.error statistic p.value am <chr> <dbl> <dbl> <dbl> <dbl> <list> 1 (Intercept) 6.10 0.353 17.3 8.36e-17 <tibble [3 × 5]> 2 vs 0.0738 0.239 0.308 7.60e- 1 <tibble [3 × 5]> 3 mpg -0.145 0.0200 -7.24 5.63e- 8 <tibble [3 × 5]>
方案2:rlang符号注入(无字符串操作)
如果希望从公式生成阶段就避免项名错误,可通过rlang符号语法直接注入列名,完全避免paste类字符串拼接的繁琐和特殊字符兼容风险:
fits <- tibble(mtcars) %>% summarise(across(c(vs, am), ~list(tidy(lm( # 将当前列名字符串转为rlang符号直接注入公式 wt ~ !!rlang::sym(cur_column()) + mpg, # 显式指定当前数据框,避免环境查找歧义 data = cur_data() )))))
注:方案中使用的
rlang::sym()+!!属于非标准评估类语法,和你提到的{{.x}}、rlang::as_name()属于同一语法体系,符合优雅性要求。
内容的提问来源于stack exchange,提问作者andrew_reece
相关产品推荐
相关产品推荐

