如何使用lag函数为R数据框添加最近NoShow日期列?
需求:为分组用户添加最近一次未赴约日期列
我有一个包含Person、NoShow和date列的DataFrame:
Person NoShow date 1 123 0 2019-01-01 2 123 1 2019-04-01 3 123 0 2020-01-01 4 123 1 2021-01-01 5 123 0 2021-04-30 6 123 0 2022-01-05 7 334 0 2019-07-07 8 334 1 2019-10-11 9 334 1 2020-07-07 10 334 0 2021-01-04
创建该DataFrame的代码:
df <- data.frame(Person = c('123','123','123','123','123','123','334','334','334','334'), NoShow = c(0,1,0,1,0,0,0,1,1,0), date = c('2019-01-01','2019-04-01','2020-01-01','2021-01-01','2021-04-30','2022-01-05','2019-07-07','2019-10-11','2020-07-07','2021-01-04') )
我已经通过lag函数创建了两个新列:
prior_noshow:标识用户是否有过之前未赴约的记录prior_noshow_f:统计用户之前未赴约的次数
创建这两个列的代码:
library(tidyverse) df %>% group_by(Person) %>% mutate(prior_noshow = lag(as.numeric(cumsum(NoShow) > 0)), prior_noshow_f = lag(cumsum(NoShow)))
添加后的DataFrame如下:
Person NoShow date prior_noshow prior_noshow_f <chr> <dbl> <chr> <dbl> <dbl> 1 123 0 2019-01-01 NA NA 2 123 1 2019-04-01 0 0 3 123 0 2020-01-01 1 1 4 123 1 2021-01-01 1 1 5 123 0 2021-04-30 1 2 6 123 0 2022-01-05 1 2 7 334 0 2019-07-07 NA NA 8 334 1 2019-10-11 0 0 9 334 1 2020-07-07 1 1 10 334 0 2021-01-04 1 2
现在需要添加prior_noshow_date列,显示每位用户最近一次未赴约的日期。例如:
- 第3、4行的
prior_noshow_date应为2019-04-01 - 第5、6行应为
2021-01-01
解决方案
可以通过标记未赴约日期、向下填充最近日期再偏移的方式实现,代码如下:
library(tidyverse) df %>% group_by(Person) %>% mutate( # 标记未赴约的日期,非未赴约行设为NA noshow_date = ifelse(NoShow == 1, date, NA), # 向下填充最近的未赴约日期,再用lag偏移一行得到"之前"的记录 prior_noshow_date = lag(fill(noshow_date, .direction = "down")) ) %>% # 保留之前的两个统计列 mutate( prior_noshow = lag(as.numeric(cumsum(NoShow) > 0)), prior_noshow_f = lag(cumsum(NoShow)) ) %>% select(-noshow_date) # 移除中间辅助列
运行后得到的结果:
Person NoShow date prior_noshow_date prior_noshow prior_noshow_f <chr> <dbl> <chr> <chr> <dbl> <dbl> 1 123 0 2019-01-01 NA NA NA 2 123 1 2019-04-01 NA 0 0 3 123 0 2020-01-01 2019-04-01 1 1 4 123 1 2021-01-01 2019-04-01 1 1 5 123 0 2021-04-30 2021-01-01 1 2 6 123 0 2022-01-05 2021-01-01 1 2 7 334 0 2019-07-07 NA NA NA 8 334 1 2019-10-11 NA 0 0 9 334 1 2020-07-07 2019-10-11 1 1 10 334 0 2021-01-04 2020-07-07 1 2
逻辑说明
- 标记未赴约日期:用
ifelse筛选出NoShow=1的行,保留对应日期,其余行设为NA; - 填充最近日期:
fill(..., .direction = "down")会把每个未赴约日期向下填充,直到遇到下一个未赴约日期,确保后续行能拿到最近的未赴约记录; - 偏移得到"之前"的记录:
lag函数将填充后的日期整体向后偏移一行,让每一行对应到当前记录发生前的最近未赴约日期; - 最后移除中间辅助列,保持DataFrame结构整洁。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

