R语言按ID统计唯一分类属性计数的频率分布实现方法
解决方案
原代码错误原因
原有dplyr代码的summarise步骤中,length(manufacturer) >0仅判断当前ID下是否存在记录,所有分组都会返回TRUE,既没有做厂商去重,也没有统计唯一值数量,因此最终仅返回总ID个数,不符合需求。
方法1:dplyr 实现(适配中小规模数据)
代码自动识别数据中单个ID对应的最大厂商数量,自动补全中间计数为0的项,无需硬编码上限:
library(dplyr) library(tidyr) df %>% group_by(ID) %>% # 计算每个ID对应的去重后厂商数量 summarise(count_manuf = n_distinct(manufacturer), .groups = "drop") %>% # 统计每个厂商数对应的ID个数 count(count_manuf, name = "count_ID") %>% # 补全从最小厂商数到最大厂商数之间缺失的项,缺失值填0 complete( count_manuf = seq(min(count_manuf), max(count_manuf)), fill = list(count_ID = 0) )
运行输出完全匹配预期格式:
# A tibble: 4 × 2 count_manuf count_ID <int> <int> 1 1 1 2 2 1 3 3 0 4 4 2
方法2:data.table 实现(适配百万行大规模数据)
针对百万行级数据集,data.table的运行速度和内存占用表现远优于dplyr,代码如下:
library(data.table) # 将数据框转为data.table格式 setDT(df) # 第一步:按ID分组统计去重后的厂商数量 id_count <- df[, .(count_manuf = uniqueN(manufacturer)), by = ID] # 第二步:自动获取最大厂商数,生成完整序列,补全0计数 max_n <- max(id_count$count_manuf) result <- data.frame( count_manuf = 1:max_n, count_ID = tabulate(id_count$count_manuf, nbins = max_n) )
注:这里用内置的
tabulate()函数做频率统计,比循环判断的效率高一个量级,百万行数据可以在毫秒级完成计算。
关键注意点
- 统计分组内唯一值数量不要直接用
length(),该函数仅返回分组总行数,不会做去重;dplyr用n_distinct()、data.table用uniqueN()实现去重计数 - 所有统计上限均通过数据实际计算得到的最大值自动生成,不需要提前硬编码,适配任意取值范围
- 若不需要补全计数为0的项,删掉
complete()(dplyr版)或生成完整序列的步骤即可,直接返回有计数的结果
内容的提问来源于stack exchange,提问作者logjammin
相关产品推荐
相关产品推荐

