基于ID列合并多行数据:保留多列并求和指定列(R dplyr)
问题描述
我有一个临床研究的大型DataFrame(1000行×1000列),这里用健身房用户数据举例:每个用户有1条主数据行(包含900+个人信息列),每次到店对应1条访问行(记录各区域停留时间)。主数据行的时间列值为NA,访问行的主信息列值为NA,存在部分缺失值。
示例数据
#master row information# #visit row information gym_id name weight height (900+ col data) time_gym time_sauna time_cafe 001 Alice 130 60 ... NA NA NA 001 Alice NA NA ... 20 NA 10 001 Alice NA NA ... 60 NA NA 002 Bob 200 70 ... NA NA NA 003 Eve 140 70 ... NA NA NA 003 Eve NA NA ... 100 10 NA 003 Eve NA NA ... 80 NA NA 003 Eve NA NA ... 50 15 NA 003 Eve NA NA ... 50 10 NA 003 Eve NA NA ... 60 NA 5 003 Eve NA NA ... 40 NA NA 003 Eve NA NA ... 80 5 NA ....
生成示例数据的代码
gym_id <- c(1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3) name <- c('Alice', 'Alice', 'Alice', 'Bob', "Eve", "Eve", "Eve", "Eve", "Eve", "Eve", "Eve", "Eve") weight <- c(130, NA, NA, 200, 140, NA, NA, NA, NA, NA, NA, NA) height <- c(60, NA, NA, 70, 70, NA, NA, NA, NA, NA, NA, NA) time_gym <- c(NA, 20, 60, NA, NA, 100, 80, 50, 50, 60, 40, 80) time_sauna <- c(NA, NA, NA, NA, NA, 10, NA, 15, 10, NA, NA, 5) time_cafe <- c(NA, 10, NA, NA, NA, NA, NA, NA, NA, 5, NA, NA) gym <- data.frame(gym_id, name, weight, height, time_gym, time_sauna, time_cafe)
期望结果
#master row information# #visit row information gym_id name weight height (900+ col data) total_gym total_sauna total_cafe 001 Alice 130 60 ... 80 0 10 002 Bob 200 70 ... 0 0 0 003 Eve 140 70 ... 460 40 5
当前遇到的问题
尝试用mutate()、group_by()、summarise()组合时,会丢失大量列,比如:
gym %>% group_by(gym_id) %>% summarise(total_gym = sum(time_gym), total_sauna = sum(time_sauna))
逐个指定900+主信息列来保留不现实,拆分数据框的临时方案会给后续分析带来麻烦,求高效解决方法。
解决方案
可以利用dplyr的group_by()结合across()批量处理两类列,无需逐个指定列名:
简洁实现代码
library(dplyr) gym_merged <- gym %>% # 按用户唯一标识分组(用gym_id+name避免重名冲突) group_by(gym_id, name) %>% summarise( # 批量处理主信息列:取每组中非NA的唯一有效值(主数据行仅1条有效数据) across(-starts_with("time_"), ~ first(na.omit(.))), # 批量计算时间列总和,自动添加total_前缀,NA自动按0计算 across(starts_with("time_"), ~ sum(., na.rm = TRUE), .names = "total_{.col}") ) %>% # 把total_time_前缀简化为total_ rename_with(~ gsub("total_time_", "total_", .), starts_with("total_time_")) %>% ungroup()
关键细节说明
across(-starts_with("time_")):通过排除时间列,直接批量处理所有主信息列,不用手动输入900+列名;如果主信息列有统一前缀,也可以用starts_with("主信息前缀")精准匹配sum(., na.rm = TRUE):求和时忽略NA,确保没有访问记录的用户总和显示为0.names = "total_{.col}":自动给求和后的列添加total_前缀,无需手动改名
这个方法高效处理批量列,同时保留所有主信息,完全符合需求。
内容的提问来源于stack exchange,提问作者Sam K
相关产品推荐
相关产品推荐

