如何使用dplyr按分组列条件跨多列实现泛化汇总
报错的根本原因
在across的求值规则里,我们传入的函数(比如写在myfns里的lambda表达式),默认的求值语境只会绑定当前正在遍历计算的单列向量,其他分组内的列不会自动注入这个语境里。
- 你写的
~.[[which.min(j)]]里,.仅代表当前被遍历的列,j没有被纳入这个函数的可访问范围,自然会触发“找不到j对象”的报错。 - 之前你逐列手写
best_a = a[[which.min(j)]]的方式之所以能跑通,是因为这段代码是在整个分组的全列tibble语境下执行的,a和j同属一个语境,可以互相引用,不存在隔离问题。
通用泛化实现方法
只需要在best值的计算逻辑里,用dplyr提供的pick()函数,显式把参考列j引入当前函数的可访问语境即可,不需要逐列手写逻辑:
library(dplyr) # 定义通用函数集合 myfns <- list( med = ~median(.), # 用pick(j)在函数语境中获取当前分组的全量j列向量 best = ~.[[which.min(pick(j))]] ) # 跨列批量计算 myDF %>% group_by(i) %>% summarize( across(where(is.numeric), myfns, .names = "{fn}_{col}"), .groups = "drop" )
输出结果验证
运行结果和逐列手写的输出完全匹配:
# A tibble: 3 × 9 i med_j best_j med_a best_a med_b best_b med_c best_c <int> <dbl> <dbl> <int> <int> <int> <int> <int> <int> 1 1 0.217 -0.542 4 7 7 7 4 4 2 2 0.689 0.596 6 8 6 6 6 8 3 3-0.213 -1.28 5 9 2 1 7 7
灵活调整提示:
- 如果不想让参考列
j也参与best值的计算(也就是不需要生成冗余的best_j列),可以把across的列选择条件从where(is.numeric)改成where(is.numeric) & !all_of("j"),或者直接指定需要计算的目标列名向量。- 如果使用的是较早版本的dplyr(无
pick()函数),可以把best函数里的pick(j)替换成cur_data_all()$j,效果完全一致。
内容的提问来源于stack exchange,提问作者ztl
相关产品推荐
相关产品推荐

