如何在dplyr::across()中使用返回多值的自定义函数
dplyr::across()单次遍历计算多统计量的实现方案
核心实现思路
across默认会自动展开返回值为命名向量的函数输出,只要自定义函数返回带名称的一维向量,即可直接生成扁平化的独立列,无需额外拆包操作,每列仅遍历一次,完全避免重复计算。
方案1:返回命名向量(最优解)
该方案无需额外依赖包,输出和常规多匿名函数写法完全一致:
# 自定义统计函数,返回命名向量 calc_multi_stats <- function(x) { c( mean = mean(x, na.rm = TRUE), sd = sd(x, na.rm = TRUE), median = median(x, na.rm = TRUE), missing = sum(is.na(x)) ) } # 调用across批量处理 library(dplyr) result <- mtcars %>% summarise( across(c(mpg, disp, hp, drat, wt), calc_multi_stats, .names = "{.col}_{.fn}") )
输出列名为mpg_mean、mpg_sd、disp_mean等,和常规传入list(mean = ~mean(.x), sd = ~sd(.x))的输出格式完全一致,无嵌套结构。
方案2:返回数据框时用unpack拆包
如果你的自定义逻辑必须返回数据框结构(例如返回多组关联的分类统计结果),不要使用unnest()处理这类场景——unnest()是针对行维度的展开操作,tidyr::unpack()才是针对列维度嵌套结构的拆包函数:
# 返回数据框的自定义函数 calc_stats_df <- function(x) { tibble( mean = mean(x, na.rm = TRUE), sd = sd(x, na.rm = TRUE), range = max(x, na.rm = TRUE) - min(x, na.rm = TRUE) ) } # 调用后拆包 library(tidyr) result <- mtcars %>% summarise(across(c(mpg, disp, hp), calc_stats_df)) %>% unpack(where(is.data.frame), names_sep = "_")
names_sep = "_"参数会自动生成{原列名}_{统计量名}格式的列名,和常规across输出规则对齐。
命名规则自定义
如果需要调整列名格式,直接修改across的.names参数即可,和常规多函数写法的配置完全通用,例如:
# 生成 统计量名_列名 格式的列名 result <- mtcars %>% summarise(across(c(mpg, hp), calc_multi_stats, .names = "{.fn}_{.col}"))
内容的提问来源于stack exchange,提问作者Dan Chaltiel
相关产品推荐
相关产品推荐

