R语言高效处理大数据框:按分组保留众数对应行的优化方案
R语言高效处理大数据量DataFrame的分组众数保留需求
需求说明
- 按
team列分组 - 每个分组内,保留
assists列出现次数最多的值对应的行;若多个值出现次数相同(如示例中team C的assists=9和1),取最后出现的那个众数 - 每个
points值在对应分组下仅保留一行
示例数据
df <- data.frame(points=c(1, 2, 4, 3, 4, 8, 3, 3, 2), assists=c(6, 6, 5, 6, 6, 9, 9, 1, 1), team=c('A', 'A', 'A', 'A', 'A', 'C', 'C', 'C', 'C'))
原始数据输出:
points assists team 1 1 6 A 2 2 6 A 3 4 5 A 4 3 6 A 5 4 6 A 6 8 9 C 7 3 9 C 8 3 1 C 9 2 1 C
期望处理结果
df2 <- data.frame(points=c(1, 2, 3, 4, 8, 3), assists=c(6, 6, 6, 6, 1, 1), team=c('A', 'A', 'A', 'A', 'C', 'C'))
结果输出:
points assists team 1 1 6 A 2 2 6 A 3 3 6 A 4 4 6 A 5 8 1 C 6 3 1 C
高效解决方案(替代for循环)
针对300万行的大数据量,推荐使用向量化分组运算的data.table或dplyr包,性能远优于逐行遍历的for循环。
方案1:使用data.table(性能最优,适合超大数据)
library(data.table) # 转换为data.table格式 setDT(df) result <- df[, { # 计算每个assists的出现次数和最后出现的行号 assist_stats <- .SD[, .(count = .N, last_row = .I[.N]), by = assists] # 筛选出计数最大且最后出现的assists值 target_assist <- assist_stats[count == max(count), assists[order(-last_row)][1]] # 保留对应assists的行,再按points去重(留最后一行) .SD[assists == target_assist, .SD[.N], by = points] }, by = team] # 转换回data.frame并重置行名 setDF(result) rownames(result) <- NULL
方案2:使用dplyr(语法更直观)
library(dplyr) result <- df %>% # 计算每个team+assists组合的计数和最后出现位置 group_by(team, assists) %>% mutate(count = n(), last_row = row_number()) %>% ungroup() %>% group_by(team) %>% # 筛选当前分组内符合要求的assists行 filter(count == max(count), last_row == max(last_row[count == max(count)])) %>% ungroup() %>% # 按team+points去重,保留最后一行 group_by(team, points) %>% slice_tail(n = 1) %>% ungroup() %>% # 整理列顺序并重置行名 select(points, assists, team) %>% arrange(team, points) rownames(result) <- NULL
方案说明
- 两个方案均采用向量化分组逻辑,避免逐行遍历,处理300万行数据的速度会比for循环提升数倍甚至数十倍
data.table在超大数据场景下性能略优于dplyr,数据量极大时优先选择- 核心逻辑:先在分组内确定目标assists值(众数,次数相同时取最后出现的),再对每个
team+points组合保留唯一行
内容的提问来源于stack exchange,提问作者Fred
相关产品推荐
相关产品推荐

