R语言tidyverse分组取最高频值 并列时取最近日期对应值
tidyverse 实现分组按规则取value的方案
核心思路是给每条记录计算三个排序权重,分组排序后直接取每组最后一条记录即可,三个权重的优先级完全匹配需求:
- 第一权重:当前value在同ID组内的出现频次,频次越低排序越靠前
- 第二权重:记录对应的日期,日期越早排序越靠前
- 第三权重:记录在原始数据中的行位置,位置越靠上排序越靠前
排序完成后每组最末尾的记录,就同时满足「频次最高、同频次选日期最新、同日期选原始位置最靠下」的要求。
完整可复现代码
# 加载tidyverse包 library(tidyverse) # 构造示例数据集 df <- tribble( ~ID, ~value, ~date, "001", "A", as.Date("2015-12-06"), "001", "A", as.Date("2015-12-07"), "001", "A", as.Date("2015-12-08"), "002", "B", as.Date("2015-12-09"), "002", "C", as.Date("2015-12-10"), "003", "A", as.Date("2015-12-11"), "003", "B", as.Date("2015-12-12"), "002", "B", as.Date("2015-12-13"), "004", "D", as.Date("2015-12-13"), "004", "R", as.Date("2015-12-13") ) # 核心处理逻辑 result <- df %>% # 生成原始行号,保留数据原始位置顺序 mutate(original_row = row_number()) %>% # 按ID、value分组,统计每个value在对应ID下的出现次数 group_by(ID, value) %>% mutate(value_count = n()) %>% ungroup() %>% # 按ID分组处理 group_by(ID) %>% # 按三个权重升序排序,同ID组内排序 arrange(value_count, date, original_row, .by_group = TRUE) %>% # 取每组最后一行,仅保留需要的字段 slice_tail(n = 1) %>% ungroup() %>% select(ID, value)
运行结果
执行代码后输出的result和预期完全一致:
# A tibble: 4 × 2 ID value <chr> <chr> 1 001 A 2 002 B 3 003 B 4 004 R
逻辑校验
- ID=001:value A共出现3次,频次最高,直接选中A
- ID=002:value B出现2次、C出现1次,B频次更高,选中B
- ID=003:A、B各出现1次频次持平,B对应日期2015-12-12晚于A的2015-12-11,选中B
- ID=004:D、R各出现1次频次持平,日期完全相同,R在原始数据中位置更靠下,选中R
内容的提问来源于stack exchange,提问作者John Thomas
相关产品推荐
相关产品推荐

