如何结合dplyr的group_by、summarise、across实现多函数输出?
按分组批量计算多列与指定列的相关性(tidyverse高效方案)
测试数据
tTest = tibble(Cells = rep(c("C1", "C2", "C3"), times = 3), Gene = rep(c("G1", "G2", "G3"), each = 3), Experiment_score = 1:9, Pattern1 = 1:9, Pattern2 = -(1:9), Pattern3 = 9:1) %>% group_by(Gene)
需求
按Gene分组,计算Experiment_score与所有以Pattern开头的列的相关性,输出相关系数和对应的p值。
最初尝试的问题
尝试用across结合返回列表的包装函数corList,但返回嵌套的列表列,结果不符合预期:
# 返回列表的包装函数 corList = function(x, y) { result = cor.test(x, y) return(list(stat = result$estimate, pval = result$p.value)) } # 执行后得到异常的嵌套列结果 tTest %>% summarise(across(starts_with("Pattern"), ~ corList(Experiment_score, .x), .names = "{.col}_corr_{.fn}"))
高效解决方案(无需转长表)
核心是让相关性包装函数返回tibble而非列表/向量,这样across可以直接将结果展开为多列,避免转长表的性能损耗:
1. 定义返回tibble的相关性函数
cor_tibble = function(x, y) { res = cor.test(x, y) tibble(corr = res$estimate, corr_pval = res$p.value) }
2. 结合across批量计算
tTest %>% summarise(across(starts_with("Pattern"), ~ cor_tibble(Experiment_score, .x), .names = "{.col}_{.value}"))
执行后会得到宽表格式的结果,每个Pattern列对应两列输出:例如Pattern1_corr(相关系数)、Pattern1_corr_pval(p值),完全匹配需求,且无需转长表,在百万行+数十个Pattern列的场景下,内存占用和计算效率远优于转长表方法。
原转长表的不完善方案
以下是最初的解决方案,虽然能得到正确结果,但数据量大时会因pivot_longer导致数据膨胀,严重影响处理效率:
# 返回向量的包装函数 corVect = function(x, y) { result = cor.test(x, y) return(c(stat = result$estimate, pval = result$p.value)) } # 转长表计算后再转回宽表 tTest %>% pivot_longer(starts_with("Pattern"), names_to = "Pattern", values_to = "Strength") %>% group_by(Gene, Pattern) %>% summarise(CorrVal = corVect(Experiment_score, Strength)) %>% mutate(CorrType = c("corr", "corr_pval")) %>% pivot_wider(id_cols = c(Gene, Pattern), names_from = CorrType, values_from = CorrVal)
内容的提问来源于stack exchange,提问作者Martingales
相关产品推荐
相关产品推荐

