R语言:按id分组,判断最近一个月的product_code是否为历史未出现值
问题:识别每个ID最近一个月是否出现新的产品编码
我有一个数据集,每个ID随时间会接收不同的product_code,date字段跨度近10年。需要识别每个ID在其product_code记录的最近一个月内,是否出现了历史记录中从未有过的product_code。
数据示例
原始数据创建代码
df <- data.frame(id=c(1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4), product_code=c("178","321","252","147","178","321","252","147","178","322","253","698", "411","322","253","670"), date=c("2022-10-10","2022-10-10","2022-10-10","2022-10-10","2022-11-10","2022-11-10","2022-11-10", "2022-11-10","2022-12-10","2022-12-10","2022-12-10","2022-12-10","2023-02-10", "2023-02-10","2023-02-10","2023-02-10") )
按ID排序后的数据
df %>% arrange(id) id product_code date 1 1 178 2022-10-10 2 1 178 2022-11-10 3 1 178 2022-12-10 4 1 411 2023-02-10 5 2 321 2022-10-10 6 2 321 2022-11-10 7 2 322 2022-12-10 8 2 322 2023-02-10 9 3 252 2022-10-10 10 3 252 2022-11-10 11 3 253 2022-12-10 12 3 253 2023-02-10 13 4 147 2022-10-10 14 4 147 2022-11-10 15 4 698 2022-12-10 16 4 670 2023-02-10
预期输出
id new_product_code 1 1 2 0 3 0 4 1
错误代码及问题分析
我尝试用以下代码但无法得到正确结果:
df %>% group_by(id) %>% mutate(new_product_code=if_else(any(product_code[date>max(date)-30]) %in% product_code[date<max(date)-30],1,0)) %>% select(id,new_product_code)
问题出在三点:
- 日期类型未转换:原数据的date是字符串,
max(date)-30会按字符串运算,无法得到正确的时间范围 - 逻辑判断反向:需求是检查最近一个月的编码是否有从未在历史出现过的,但代码判断的是最近一个月的编码是否在历史里,逻辑完全相反
- 结果处理错误:
mutate会给每一行生成结果,最终会得到重复的ID记录,而我们需要每个ID一行的汇总结果
正确解决方案
先将date转换为日期类型,再分组后通过对比最近一个月和历史的产品编码集合来判断:
library(dplyr) # 转换日期类型,分组处理 df %>% mutate(date = as.Date(date)) %>% group_by(id) %>% summarise( # 计算最近一个月的起始日期 recent_month_start = max(date) - 30, # 提取最近一个月的所有产品编码(去重) recent_products = list(unique(product_code[date >= recent_month_start])), # 提取历史所有产品编码(最近一个月之前,去重) history_products = list(unique(product_code[date < recent_month_start])), # 判断是否有最近的产品不在历史中 new_product_code = as.integer(any(!unlist(recent_products) %in% unlist(history_products))) ) %>% select(id, new_product_code)
运行后会得到完全符合预期的输出。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

