R语言dplyr多变量分组时为数据框生成组内编号的实现方法
问题背景
目前已有多个同类型的R数据框分组编号问题解答,但均未涉及多分组变量下的嵌套编号场景,现有方案无法适配需求。
测试数据
运行以下代码可构造测试用数据集:
library(dplyr) df <- tibble( s1 = c("111", "111", "111", "112", "112", "114", "114", "115"), s2 = c(rep("A", 5), rep("B", 3)), val = rnorm(8) )
需求描述
需要在s2的分组范围内为s1分配分组ID,ID规则为:相同s2下,同一个s1的ID值一致,s1取值变化时ID递增,s2取值变化时ID重置为1重新计数,期望输出结构如下:
# A tibble: 8 x 4 s1 s2 val id <chr> <chr> <dbl> <dbl> 1 111 A -0.465 1 2 111 A 0.871 1 3 111 A 0.821 1 4 112 A 0.562 2 5 112 A 0.197 2 6 114 B -0.743 1 7 114 B 0.0847 1 8 115 B -1.05 2
已验证无效的方案
以下写法均无法实现上述编号逻辑:
# 仅按s1分组编号,s2切换时不会重置计数 df %>% group_by(s1) %>% mutate(id = row_number()) # 按s1+s2联合分组生成行号,同组内相同s1的行号会逐行递增,无法拿到统一ID df %>% group_by(s1, s2) %>% mutate(id = row_number()) # 仅按s2分组生成行号,不会识别s1的取值变化 df %>% group_by(s2) %>% mutate(id = row_number()) # 其余错误写法 df %>% group_by(s1) %>% mutate(id = row_number(s2)) df %>% group_by(s1) %>% mutate(id = cur_group_id()) df %>% group_by(s1, s2) %>% mutate(id = cur_group_id())
实现方案
核心逻辑是先按s2拆分数据分组,再在每个s2分组内,按s1的出现顺序生成连续的分组ID,两种常用实现写法如下:
写法1:通用匹配写法(兼容各dplyr版本)
df %>% group_by(s2) %>% mutate(id = match(s1, unique(s1))) %>% ungroup()
逻辑说明:
group_by(s2)保证所有计算仅在单个s2分组内执行,s2取值变化时计算自动重置unique(s1)按出现顺序提取当前s2分组内所有不重复的s1值match()返回每一行s1在不重复s1列表中的位置,刚好符合编号规则:同个s1拿到相同ID,s1变化ID递增,s2切换ID从1重启
写法2:专用连续ID函数(dplyr 1.0.0及以上版本可用)
df %>% group_by(s2) %>% mutate(id = consecutive_id(s1)) %>% ungroup()
consecutive_id()会按列值的连续变化生成递增ID,配合s2分组使用时,刚好实现组内按s1变化生成编号的需求,写法更简洁。
两种写法运行结果和期望输出完全一致。
内容的提问来源于stack exchange,提问作者Earlien
相关产品推荐
相关产品推荐

