优化group_by与summarize运行效率——千万级员工数据分组统计需求
问题描述
我有一个包含约1000万条员工记录的data frame df,每条记录包含员工ID、工作所在city及company字段:
ID city company 1 NYC ABC 2 BOS ABC 1 NYC DEF 3 SEA GHI
我需要按ID和city分组,统计每位员工任职的公司数量,期望结果如下:
ID city count 1 NYC 2 2 BOS 1 3 SEA 1
当前使用的代码为:df %>% group_by(ID, city) %>% summarize(count = n_distinct(company)),但运行耗时极长,我的设备可支持高计算量操作,却无法高效运行这段代码,求更高效的实现方案。
编辑说明:已修正为n_distinct(company),而非n_distinct(ID)
高效实现方案
以下几种方法在处理千万级数据时性能远优于原tidyverse代码:
1. 使用data.table(性能最优)
data.table在大数据量分组计算上的效率远超dplyr,写法如下:
library(data.table) setDT(df)[, .(count = uniqueN(company)), by = .(ID, city)]
uniqueN()是data.table内置的高效去重计数函数,配合setDT()将data.frame转换为data.table后,分组计算的速度会有数量级提升。
2. tidyverse优化版:先去重再计数
原代码慢的核心原因是分组后对每组做去重计数,先全局去重再分组计数可以大幅减少计算量:
df %>% distinct(ID, city, company) %>% group_by(ID, city) %>% summarize(count = n())
先通过distinct()保留唯一的ID-city-company组合,再分组统计行数,避免了每组内重复的去重操作,性能会显著提升。
3. Base R原生方法
无需加载第三方包,可通过两种方式实现:
- 直接使用
aggregate():
aggregate(company ~ ID + city, data = df, FUN = function(x) length(unique(x)))
- 先去重再统计:
# 保留唯一的ID-city-company组合 unique_df <- unique(df[, c("ID", "city", "company")]) # 统计每组的数量 count_table <- table(unique_df$ID, unique_df$city) # 转换为目标格式的data frame result <- as.data.frame(count_table) colnames(result) <- c("ID", "city", "count")
内容的提问来源于stack exchange,提问作者questionmark
相关产品推荐
相关产品推荐

