You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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数量,统计规则为:

  1. 先按ID维度聚合归类:存在任意treatmen==1记录的ID归为treatment=1组,所有记录均为treatmen==0的ID归为treatment=0组;同理,存在任意event==1记录的ID归为event=1组,所有记录均为event==0的ID归为event=0组
  2. 最终输出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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 08:48:25