在R语言中按分组随时间创建条件递增的分类变量
问题
我有一个按用户分组、按时间排序的数据框,其中包含一个表示用户状态的二进制字段Status(0代表退出状态,1代表处于状态)。我需要为每个用户生成一个Status_Count字段:
- 当用户进入或重新进入状态(即从0变为1)时,计数器递增
- 同一状态周期内的所有时间点,计数器保持相同值
- 退出状态时(Status=0),计数器显示0
期望输出
Date User_ID Status Status_Count 01/01/2022 1 0 0 01/02/2022 1 0 0 01/03/2022 1 1 1 01/04/2022 1 1 1 01/05/2022 1 1 1 01/06/2022 1 0 0 01/07/2022 1 0 0 01/08/2022 1 1 2 01/09/2022 1 1 2 01/10/2022 1 0 0 01/11/2022 1 0 0 01/12/2022 1 0 0 01/01/2022 2 0 0 01/02/2022 2 1 1 01/03/2022 2 1 1 01/04/2022 2 1 1 01/05/2022 2 0 0 01/06/2022 2 0 0 01/07/2022 2 1 2 01/08/2022 2 1 2 01/09/2022 2 0 0 01/10/2022 2 0 0 01/11/2022 2 1 3 01/12/2022 2 0 0
示例数据
Date <- rep(seq(as.Date('2022-01-01'), as.Date('2022-12-01'), by = "month"), 2) User_ID <- c(rep.int(1, 12), rep.int(2, 12)) Status<- c(0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0) Status_Counter <- c(0, 0, 1, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2, 0, 0, 3, 0) Example_Data <- data.frame(Date, User_ID, Status, Status_Counter)
尝试的代码(存在问题)
library(dplyr) Example_Data <- Example_Data %>% group_by(User_ID) %>% dplyr::mutate(Counter = case_when( Event == 1 & (Status != lag(Status, 1) | is.na(lag(Status, 1))) ~ cumsum(Status), Event == 1 ~ cumsum(Status), TRUE ~ 0))
解决方案
核心思路是先识别每个用户的状态进入事件(从0切换到1),再基于这些事件生成分组计数器,最后对退出状态的行做置0处理。用dplyr实现的完整代码如下:
library(dplyr) Example_Data <- Example_Data %>% group_by(User_ID) %>% # 标记状态进入事件:从0→1的时刻标记为1,其余为0 mutate(enter_event = ifelse(Status == 1 & (is.na(lag(Status)) | lag(Status) == 0), 1, 0), # 累加事件得到状态周期的序号 cycle_num = cumsum(enter_event), # 状态为0时计数器置0,否则保留周期序号 Status_Count = ifelse(Status == 0, 0, cycle_num)) %>% # 移除中间辅助列(可选操作) select(-enter_event, -cycle_num) %>% ungroup()
代码说明
enter_event:精准捕捉每个用户的状态进入节点,只有当当前状态为1且上一个状态为0(或为用户第一条记录)时,才标记为1cycle_num:对进入事件做累加,每遇到一个进入事件序号就加1,同一状态周期内的所有行共享同一个序号Status_Count:将状态为0的行计数器置为0,状态为1的行保留对应的周期序号,完全匹配需求的输出格式
运行后即可得到你期望的Status_Count字段。
内容的提问来源于stack exchange,提问作者SharkSandwich
相关产品推荐
相关产品推荐

