在R中使用dplyr生成分组切换时重置的序列变量n
问题:使用dplyr生成按group切换重置的序列变量
n 给定如下R数据集:
id <- c(1,1,1,1,1,2,2,2,2,3,3) time <- c(2000,2001,2002,2003,2004,2000,2001,2002,2003,2000,2001) group <- c(0,0,1,0,0,0,1,0,1,0,0) df_temp <- data.frame(id, time, group)
需要创建一个名为n的新变量,规则是:每当group从0切换到1或从1切换到0时,重置序列计数,预期的n序列为:
n <- c(1,2,1,1,2,1,1,1,1,1,2)
尝试了以下代码,但结果不符合预期:
df_temp2 <- df_temp %>% arrange(id, time, group) %>% group_by(group) %>% mutate(n=seq_along(group))
解决方案
你之前的错误在于直接按group分组计数,这无法区分同一个group在不同时间段的连续区间(比如id=1的group=0出现了两段连续区间)。正确的思路是:先按id分组,识别出每个id内连续相同的group分段,再在每个分段内生成从1开始的序列。
完整的dplyr代码如下:
library(dplyr) df_result <- df_temp %>% # 先按id和时间排序,确保观测顺序正确 arrange(id, time) %>% # 按id分组,处理每个id内的group切换 group_by(id) %>% # 生成连续相同group的分段标识:切换group时分段+1 mutate(segment = cumsum(group != lag(group, default = first(group)))) %>% # 在id和segment的分组内生成序列 group_by(segment, .add = TRUE) %>% mutate(n = row_number()) %>% # 可选:移除中间用的segment列 ungroup() %>% select(-segment)
代码逻辑说明:
arrange(id, time):确保每个id的观测按时间顺序排列,这是序列计数的基础。group_by(id):每个id的group切换是独立的,必须按id分组处理。mutate(segment = cumsum(group != lag(group, default = first(group)))):lag(group, default = first(group)):取当前行的上一行group值,第一行默认用自身的group值group != lag(...):当当前group和上一行不同时返回TRUE(即1),否则返回FALSE(即0)cumsum()累加后,每个连续相同的group段会得到同一个segment值,group切换时segment自动加1
group_by(segment, .add = TRUE):在原id分组的基础上,新增segment分组,这样每个连续的group段就是一个独立分组。mutate(n = row_number()):在每个分组内生成从1开始的连续序列,满足切换group时重置计数的需求。
运行后查看结果:
> df_result # A tibble: 11 × 4 id time group n <dbl> <dbl> <dbl> <int> 1 1 2000 0 1 2 1 2001 0 2 3 1 2002 1 1 4 1 2003 0 1 5 1 2004 0 2 6 2 2000 0 1 7 2 2001 1 1 8 2 2002 0 1 9 2 2003 1 1 10 3 2000 0 1 11 3 2001 0 2
生成的n序列与预期完全一致。
内容的提问来源于stack exchange,提问作者Cherry Lim
相关产品推荐
相关产品推荐

