R语言按ID聚合后分组统计满足条件的不重复ID数量
问题背景
现有数据框df,共包含4个以ID字段标识的研究对象:a、b、c、d。单个ID可对应1条记录(如ID=b)或多条记录(如其余3个ID),每条记录包含二值型字段treatmen、event,数据构造及预览如下:
> df <- data.frame(ID = c("a","a","a", "b", "c","c","c","c","d","d","d","d"), treatment = c(0,1,1,0,0,0,0,0,0,0,0,1), event = c(0,1,0,0,1,1,1,1,0,0,1,0), stringsAsFactors=FALSE) > df ID treatment event 1 a 0 0 2 a 1 1 3 a 1 0 4 b 0 0 5 c 0 1 6 c 0 1 7 c 0 1 8 c 0 1 9 d 0 0 10 d 0 0 11 d 0 1 12 d 1 0
需求说明
需统计分组下的不重复ID数量,统计规则为:
- 先按ID维度聚合归类:存在任意
treatmen==1记录的ID归为treatment=1组,所有记录均为treatmen==0的ID归为treatment=0组;同理,存在任意event==1记录的ID归为event=1组,所有记录均为event==0的ID归为event=0组 - 最终输出event、treatment组合下的ID计数
n,需包含所有0/1组合,无对应ID的组合计数为0
期望输出格式如下:
> [some R code] event treatment n 0 0 1 0 1 0 1 0 1 1 1 2
分组逻辑核对:
- ID a、d:存在任意
treatmen==1记录,且存在任意event==1记录 - ID b:无任何
treatmen==1记录,且无任何event==1记录 - ID c:所有记录
treatmen==0,但所有记录event==1
现存问题
之前编写的dplyr代码直接按行维度的event、treatment分组后去重ID,同一ID下不同取值的记录会被拆分到多个组,导致重复计数,运行结果总计数为8,和实际4个ID的总数不符,错误代码及运行结果如下:
df %>% group_by(event, treatment) %>% distinct(ID) %>% count(event) %>% as.data.frame() %>% mutate(Percent = round((n/sum(n))*100, digits = 1)) event treatment n Percent 1 0 0 3 37.5 2 0 1 2 25.0 3 1 0 2 25.0 4 1 1 1 12.5
方案需适配百万行级数据集,保证计算效率,不限制使用dplyr、data.table等工具。
解决方案
核心逻辑:先按ID聚合得到每个ID唯一的分组标签,再做分组计数,从根源避免同一ID被拆分到多个组重复统计。因两个字段均为0/1二值,用max()判断是否存在1的效率最高(存在1则最大值为1,全0则最大值为0,完全匹配分组规则)。
dplyr实现
library(dplyr) df %>% # 第一步:按ID聚合,生成每个ID唯一的分组标签 group_by(ID) %>% summarise( treatment = max(treatment), event = max(event), .groups = "drop" ) %>% # 第二步:分组计数,.drop = FALSE保留所有0/1组合,缺失组计数自动补0 count(event, treatment, .drop = FALSE)
运行结果和期望完全一致,若需计算百分比,直接在末尾追加mutate(Percent = round(n/sum(n)*100, 1))即可。
data.table实现(百万行级数据性能更优)
library(data.table) setDT(df) # 按ID聚合 -> 分组计数 -> 补全所有0/1组合、填充缺失计数为0 df[, .(treatment = max(treatment), event = max(event)), by = ID][ , .N, by = .(event, treatment)][ CJ(event = 0:1, treatment = 0:1), on = .(event, treatment)][ is.na(N), N := 0][]
内容的提问来源于stack exchange,提问作者logjammin
相关产品推荐
相关产品推荐

