按id和var分组去重:保留出现频率最高的行(含平局处理)
解决按分组保留频率最高值的问题
嘿,针对你需要按id和var分组,对val执行去重并保留出现频率最高的行(频率相同时选字母/数字排序第一的)的需求,这里有两种简洁好用的R实现方式,完全匹配你的预期结果:
方法一:用dplyr(tidyverse风格,直观易读)
如果你平时习惯用tidyverse工具链,这种方式最容易理解:
library(dplyr) # 你的示例数据 df <- data.frame( id = rep("a", 8), var = c(rep("b", 4), rep("c", 4)), val = c("d", "d", "d", "e", "f", "f", "g", "g") ) # 核心处理逻辑 result <- df %>% # 先按id、var、val分组,统计每个val的出现次数 group_by(id, var, val) %>% tally() %>% # 按id、var分组后,先按次数降序排,次数相同则按val升序排 arrange(id, var, desc(n), val) %>% # 每个(id,var)组只取第一行 slice_head(n = 1) %>% # 去掉计数列,恢复原数据结构 select(-n) %>% ungroup() # 查看结果 print(result)
运行后输出和你的预期完全一致:
# A tibble: 2 × 3 id var val <chr> <chr> <chr> 1 a b d 2 a c f
方法二:用data.table(大数据场景更高效)
如果你的数据集规模很大,data.table的处理速度会比dplyr快不少,写法也很简洁:
library(data.table) # 转换为data.table格式 setDT(df) # 核心处理逻辑 result <- df[, .N, by = .(id, var, val)][, .SD[order(-N, val)[1]], by = .(id, var)][, -"N"] # 查看结果 print(result)
输出同样符合预期。
逻辑说明
两种方法的核心思路是一致的:
- 统计频率:先按
id、var、val组合分组,计算每个val在对应组内的出现次数; - 排序筛选:在每个
id+var的组内,优先按频率降序排列,频率相同的情况下按val的字母/数字顺序升序排列,然后取每组的第一行; - 清理结果:移除中间的计数列,得到你需要的最终结构。
这样处理既保证了保留频率最高的行,也解决了频率相同时的排序选择问题。
内容的提问来源于stack exchange,提问作者Mark White
相关产品推荐
相关产品推荐

