如何高效实现多变量基于对应条件列的id1分组汇总统计?
问题描述
我需要对多个变量基于不同列条件做分组汇总统计。具体来说,有三个总差异变量:n.diff.total_rare、n.diff.total_general、n.diff.total_specialty,对应的还有三个用于排除观测的列(na.diff.total_*系列,值为1时排除该行对应变量的观测),需要按id1分组计算汇总统计。请问有没有比我当前写的重复代码更高效、更简洁的实现方式?
示例数据框
set.seed(100) df <- data.frame( id1 = c(rep('A', 10), rep('B', 10)), id2 = stri_rand_strings(20, 1), n.diff.total_rare = sample(0:30, 20, replace=TRUE), n.diff.total_general = sample(0:30, 20, replace=TRUE), n.diff.total_specialty = sample(0:30, 20, replace=TRUE), na.diff.total_rare = sample(0:1, 20, replace=TRUE), na.diff.total_general = sample(0:1, 20, replace=TRUE), na.diff.total_specialty = sample(0:1, 20, replace=TRUE) )
当前实现代码
output_rare <- df %>% select(id1, id2, n.diff.total_rare, na.diff.total_rare) %>% filter(na.diff.total_rare == 0) %>% mutate(zero = ifelse(n.diff.total_rare == 0, 1, 0)) %>% group_by(id1) %>% summarise( min = min(n.diff.total_rare, na.rm = T), max = max(n.diff.total_rare, na.rm = T), sd = sd(n.diff.total_rare, na.rm = T), mean = mean(n.diff.total_rare, na.rm = T), zeros = sum(zero, na.rm = T) ) %>% ungroup %>% mutate(variable = 'n.diff.total_rare') output_specialty <- df %>% select(id1, id2, n.diff.total_specialty, na.diff.total_specialty) %>% filter(na.diff.total_specialty == 0) %>% mutate(zero = ifelse(n.diff.total_specialty == 0, 1, 0)) %>% group_by(id1) %>% summarise( min = min(n.diff.total_specialty, na.rm = T), max = max(n.diff.total_specialty, na.rm = T), sd = sd(n.diff.total_specialty, na.rm = T), mean = mean(n.diff.total_specialty, na.rm = T), zeros = sum(zero, na.rm = T) ) %>% ungroup %>% mutate(variable = 'n.diff.total_specialty') output_general <- df %>% select(id1, id2, n.diff.total_general, na.diff.total_general) %>% filter(na.diff.total_general == 0) %>% mutate(zero = ifelse(n.diff.total_general == 0, 1, 0)) %>% group_by(id1) %>% summarise( min = min(n.diff.total_general, na.rm = T), max = max(n.diff.total_general, na.rm = T), sd = sd(n.diff.total_general, na.rm = T), mean = mean(n.diff.total_general, na.rm = T), zeros = sum(zero, na.rm = T) ) %>% ungroup %>% mutate(variable = 'n.diff.total_general') output <- output_rare %>% rbind( output_specialty ) %>% rbind( output_general )
优化实现方案
可以通过宽表转长表的方式消除重复代码,利用tidyr::pivot_longer将多列变量整合为行,只需要一次分组汇总逻辑即可完成所有变量的统计:
library(dplyr) library(tidyr) output_opt <- df %>% # 保留分组id,将差异变量和对应排除列转成长格式 pivot_longer( cols = -c(id1, id2), names_to = c(".value", "variable"), names_pattern = "(n\\.diff\\.total|na\\.diff\\.total)_(.*)" ) %>% # 过滤需要保留的观测:排除标记为0的行 filter(`na.diff.total` == 0) %>% # 计算是否为0的标记 mutate(zero = as.integer(`n.diff.total` == 0)) %>% # 按分组id和变量名分组 group_by(id1, variable) %>% summarise( min = min(`n.diff.total`, na.rm = TRUE), max = max(`n.diff.total`, na.rm = TRUE), sd = sd(`n.diff.total`, na.rm = TRUE), mean = mean(`n.diff.total`, na.rm = TRUE), zeros = sum(zero, na.rm = TRUE), .groups = "drop" ) %>% # 调整变量名列的格式,和原输出保持一致 mutate(variable = paste0("n.diff.total_", variable))
优化说明
pivot_longer的关键作用:通过names_pattern正则匹配,将n.diff.total_xxx和na.diff.total_xxx对应起来,生成包含n.diff.total(变量值)、na.diff.total(排除标记)、variable(后缀:rare/general/specialty)的长表,避免重复处理每个变量。- 逻辑复用:所有变量的过滤、计算零标记、分组汇总逻辑只需要写一次,代码更简洁且易维护——后续新增变量时,只需要保证列名符合现有命名规则,无需修改汇总逻辑。
- 性能更优:减少了重复的数据筛选和分组操作,尤其当数据量较大时,效率提升更明显。
内容的提问来源于stack exchange,提问作者J.K.
相关产品推荐
相关产品推荐

