基于R语言的通用月度客户留存率(CRR)计算方案问询
通用月度客户留存率(CRR)计算方案及跨年异常修复
首先咱们先解决你提到的跨年CRR异常问题,再给出适配任意时长数据的通用计算逻辑。
异常原因分析
你遇到的每年1月CRR重置为0的问题,大概率是原方案在关联月份时,只提取了纯月份数字(比如把"2018 Dec"当成12,"2019 Jan"当成1),完全没结合年份判断先后顺序。程序会误以为1月的上一个月不存在(因为1 < 12),导致无法匹配到去年12月的留存客户,最终算出错误的0值。
通用解决方案(R语言)
核心思路是:先把年月转换成带年份的标准日期格式,确保跨年度的月份能正确关联;再基于每个客户的首次出现时间区分新增/留存客户,最后套用CRR公式计算。
步骤1:加载依赖包并预处理数据
我们用lubridate处理日期,dplyr做数据聚合:
library(dplyr) library(lubridate) # 你的示例数据 year_mon = c("2018 Nov", "2018 Nov", "2018 Nov", "2018 Nov", "2018 Nov", "2018 Dec", "2018 Dec", "2018 Dec", "2019 Jan", "2019 Jan", "2019 Feb", "2019 Feb", "2019 Feb") customer_id = c(1, 2, 3, 4, 5, 2, 3, 4, 3, 4, 1, 2, 3) df <- data.frame(customer_id, year_mon) # 将year_mon转换为当月第一天的日期,解决跨年月份关联问题 df <- df %>% mutate(month_date = ymd(paste0(year_mon, " 01")))
步骤2:计算每个月的核心CRR指标
我们需要先获取:
- 当月客户总数(EC)
- 当月新增客户数(NC:首次在当月出现的客户)
- 上月客户总数(SC)
# 1. 标记每个客户的首次出现月份 customer_first_month <- df %>% group_by(customer_id) %>% summarise(first_month = min(month_date)) %>% ungroup() # 2. 聚合每个月的核心数据并计算CRR monthly_metrics <- df %>% group_by(month_date) %>% summarise( EC = n_distinct(customer_id), # 期末客户数 # 计算当月新增客户数:首次出现月份等于当前月份的客户数量 NC = sum(customer_id %in% filter(customer_first_month, first_month == month_date)$customer_id) ) %>% ungroup() %>% arrange(month_date) %>% # 按时间顺序排序,确保月份关联正确 mutate( SC = lag(EC), # 关联上月客户总数(取上一行的EC值) # 计算CRR,第一个月无上月数据,设为NA CRR = ifelse(!is.na(SC), ((EC - NC)/SC)*100, NA) ) %>% # 转回原年月格式,方便阅读 mutate(year_mon = format(month_date, "%Y %b")) %>% select(year_mon, SC, EC, NC, CRR)
步骤3:查看计算结果
运行上述代码后,monthly_metrics会输出清晰的月度CRR数据:
print(monthly_metrics) # year_mon SC EC NC CRR # 1 2018 Nov NA 5 5 NA # 2 2018 Dec 5 3 0 60.0000 # 3 2019 Jan 3 2 0 66.6667 # 4 2019 Feb 2 3 1 100.0000
咱们验证几个关键节点:
- 2018 Dec:上月(Nov)有5个客户,当月留存3人(无新增),CRR=3/5*100=60%,符合预期。
- 2019 Jan:上月(Dec)有3个客户,当月留存2人(无新增),CRR≈66.67%,完美解决了跨年异常问题。
- 2019 Feb:上月(Jan)有2个客户,当月留存1人、新增2人,EC-NC=3-1=2,CRR=2/2*100=100%,计算正确。
关键细节说明
- 日期格式转换:这是解决跨年问题的核心,用
ymd()把年月转换成带年份的日期对象,程序就能正确识别2018-12的下一个月是2019-01,不会因为月份数字1<12而出错。 - 通用适配:不管你的数据有3个月还是30个月,只要年月格式统一,这个方案都能自动按时间顺序计算每个月的CRR,完全不需要硬编码月份。
- 边界处理:第一个月没有上月数据,所以CRR设为NA,你可以根据需求调整为0或者其他值。
内容的提问来源于stack exchange,提问作者ThomasPepperz
相关产品推荐
相关产品推荐

