R语言:如何基于var1和var2的变化创建按id重置的增量列var3
解决你的连续组计数问题
我清楚你的需求:在每个id分组内,只要当前行的var1或var2和前一行不同,var3就递增1;如果和前一行完全相同,var3保持不变,而且每个id的计数要从1重新开始。你之前的两种方法都没精准匹配这个需求——第一种是按id+var1+var2的唯一组合编号(如果同一id内相同组合不连续出现,编号会重复),第二种是全局累计计数(不会在新id时重置)。
下面给你三种可靠的实现方法:
方法1:用dplyr(tidyverse生态)
借助分组和窗口函数,先标记出变化的行,再累计生成编号:
library(dplyr) df <- df %>% group_by(id) %>% # 标记当前行是否是新组的起点:第一行默认是,后续行只要var1/var2和前一行不同就算 mutate(is_new_group = c(TRUE, !(var1[-1] == lag(var1) & var2[-1] == lag(var2)))) %>% # 累计计数,每次遇到新组就加1 mutate(var3 = cumsum(is_new_group)) %>% # 移除临时列(可选) select(-is_new_group) %>% ungroup() print(df)
这里用lag()函数直接获取前一行的var1和var2,比手动索引更直观,cumsum()会自动在每个id分组内重置累计值。
方法2:用data.table(高效处理大数据)
如果你习惯用data.table,可以用shift()函数实现类似逻辑:
library(data.table) setDT(df)[, var3 := cumsum(c(TRUE, !(var1 == shift(var1) & var2 == shift(var2))[-1])), by = id] print(df)
shift(var1)会在每个id分组内生成前一行的var1值,我们比较当前行和前一行的两个变量是否都相同,取反得到新组标记,再用cumsum()累计计数。
方法3:Base R(无需额外包)
用ave()函数按id分组处理,完全依靠基础R实现:
df$var3 <- ave(seq_len(nrow(df)), df$id, FUN = function(idx) { grp_var1 <- df$var1[idx] grp_var2 <- df$var2[idx] # 生成新组标记 new_group <- c(TRUE, !(grp_var1[-1] == grp_var1[-length(grp_var1)] & grp_var2[-1] == grp_var2[-length(grp_var2)])) # 累计计数 cumsum(new_group) }) print(df)
ave()会把每个id对应的行索引传给自定义函数,我们在函数内处理该分组的变量,生成连续组的编号。
这三种方法都会输出你想要的结果:
id var1 var2 var3 1 1 1 1 1 2 1 2 2 2 3 1 2 2 2 4 1 3 2 3 5 1 4 2 4 6 1 4 3 5 7 1 4 4 6 8 1 4 4 6 9 2 1 1 1 10 2 1 1 1 11 2 2 1 2 12 2 2 2 3 13 2 2 2 3 14 2 3 2 4
内容的提问来源于stack exchange,提问作者PaulR
相关产品推荐
相关产品推荐

