
做客户流失分析是数据岗最常遇到的“入门级硬骨头”看起来只是查一查哪些用户不再登录但真把探索性数据分析EDA做扎实后能直接决定后面建的模型是“能用”还是“摆设”。这次我要分享的就是一次客户流失判断项目里最关键的EDA环节。项目背景是某订阅制在线服务平台业务方希望弄清楚哪些用户正在流失为什么流失以及我们能不能在用户彻底流失之前提前捕捉到信号。适合刚接触用户分析、想系统做用户增长和风控的同学参考我会把每一步的思路、参数选择理由和踩过的坑都写出来。1. 项目定位与整体思路1.1 流失分析要回答的三个核心问题做这个项目前我先没有急着打开数据而是把业务方的需求拆成了三个问题。第一个问题什么叫流失用户不同业务对流失的定义完全不同电商可能看“最近180天无下单”SaaS可能看“合同到期后未续费”我们这个平台当时采用的是“连续90天未登录且无任何核心功能使用记录”。第二个问题流失用户长什么样他们有哪些共同特征比如注册时长、使用频次、消费金额、客服交互情况。第三个问题这些信号能不能提前量化也就是能不能用观察窗口的数据预测未来一段时间内用户的流失概率。这里面最容易被忽略的是第一问。很多分析项目上来就做建模最后发现标签口径是错的模型再花哨也没有业务价值。所以我在项目启动后第一件事是和业务方开了半小时的会把“流失”的定义固定下来并且约定后续如果业务口径有变化需要走变更流程。这个动作看起来偏管理但在实操中非常关键因为EDA阶段的所有分布分析、对比分析都依赖这个标签。1.2 为什么先从EDA下手而不是直接建模很多同学会问既然目标是“判断客户流失”为什么不直接上逻辑回归或树模型我的回答是在不知道数据长什么样的情况下建模等于蒙着眼睛开车。EDA的核心价值有三个一是验证数据质量看看有没有缺失、异常、重复二是验证业务假设比如“充值越多的用户越不容易流失”是否真的成立三是为特征工程提供线索哪些字段要衍生、哪些字段要合并、哪些字段会明显区分流失人群。我见过一个反例某个同事拿到数据后直接跑XGBoost特征里包含“最近一次登录时间距离今天的天数”模型效果看起来很好AUC到0.9但业务方根本没法用。原因就是这个特征是事后标签包含了用户已经流失的事实属于数据泄露。如果先做EDA把这个字段的分布和流失标签一起看立刻就会发现它在时间顺序上有问题。所以EDA不是“建模前随便看看”而是一个防呆校验的过程。我习惯把EDA类比成医生先问诊看舌苔再做检查症状都还没确认直接开猛药很容易出错。2. 数据准备与质量排查2.1 字段字典与业务口径对齐这个项目的数据来自三张表用户基础信息表、登录行为表、消费订单表。我先把三张表通过用户ID做了关联合并成一张宽表每一行代表一个已经注册超过90天的用户。这里有个细节如果用户注册时间不足90天还没有足够长的观察期不能简单定义为“活跃”或“流失”我在初期直接排除掉了避免把新用户漏判成流失。字段字典需要和业务方逐项确认重点看几个容易被误解的口径。比如“最近登录时间”到底是“最近一次点击行为”还是“最近一次成功登录”这两个值可能差很多。再比如“消费金额”是订单实付金额还是包含退款后的净金额我在核对时发现订单表里的金额包含了部分虚拟商品退款如果不扣除高价值用户的流失判断会被严重干扰。最终我们统一为“实际支付金额减去已退款金额”。另外用户ID在原始表里偶尔有重复。用户基础信息表应该是一用户一记录但实际跑出来发现大概有千分之一的重复。这种量级虽然不大但一旦关联到行为表会导致记录数膨胀后续聚合结果失真。所以EDA的第一步不是画图而是先用df.groupby(user_id).size().sort_values(ascendingFalse)查找重复ID并对重复记录做去重处理。import pandas as pd user_info pd.read_csv(user_info.csv) dup user_info.groupby(user_id).size().reset_index(namecnt) print(dup[dup[cnt] 1].head())2.2 缺失值与异常值的处理策略缺失值处理没有统一标准必须结合业务含义。我在这个项目里把所有特征按缺失比例分成三档缺失低于5%的连续型字段用中位数填充离散型字段用众数填充缺失在5%到30%的新增一列“该字段是否缺失”因为缺失本身可能就是信号缺失超过30%的单独评估不直接删除而是看它和流失标签的关系。举个例子用户基础信息表里的“行业类型”字段缺失率接近15%。一开始我打算直接填充“未知”但后来分组对比发现缺失行业类型的人群流失率比有明确行业标签的人群高出12个百分点。这其实反映出部分用户的注册信息不完整本身就说明这类用户对平台投入度较低。如果把缺失值简单填充成“未知”等于把这个重要信号抹掉了。所以我在最终特征里保留了“行业类型是否缺失”这个二值列。异常值的处理要更加小心。用户行为数据天生带有长尾分布比如一个极其活跃的用户可能一周登录300次另一个用户可能一年只登录两次。不能直接用3倍标准差剔除因为我发现“登录频次”的分布是典型的右偏分布。我当时的做法是先画箱线图把超过99.5%分位数的值拿出来逐个看发现有的是数据埋点重复上报有的确实是超高频用户。对于重复上报我做了一次性去重对于真实但极端的用户我在EDA阶段先保留建模阶段再考虑做对数变换或封顶。处理完缺失和异常后我重新跑了一次描述性统计特别关注“最后活跃距离今天的天数”这个字段。这个字段直接描述了用户的“沉默时间”通常不用做缺失填充因为沉默几天本身就是重要的行为信号。如果有人把这个字段强行填充成0后续所有分析都会失去意义。3. 核心特征探索3.1 用户生命周期与活跃度分布用户生命周期的探索是我最喜欢的部分因为它能把看似杂乱的行为数据归纳成几个可理解的群体。我首先计算了一个特征注册时长也就是从注册日到观察截止日的天数。然后和“最后活跃距离今天的天数”做交叉分析绘制二维分布图。结果发现注册时长超过180天的用户分布呈明显的两极分化一部分依然保持每天登录另一部分已经超过90天没有任何行为。这时候我做了第一版用户分层活跃用户、沉默用户、疑似流失用户、流失用户。分层规则很简单就是基于两个时间维度最近一次活跃距今是否超过7天、是否超过90天。分层之后各层的人数占比大概是活跃31%、沉默28%、疑似流失16%、流失25%。这个结果让业务方有些意外因为原以为流失率只有10%左右但那是只统计主动退订的用户忽略了很多“悄无声息离开”的用户。活跃度分布还需要结合功能使用深度来看。我在登录行为表里聚合出“近30天使用核心功能次数”并计算了人均次数。流失用户和活跃用户在这个指标上的差异非常明显。流失用户近30天使用次数均值只有0.3次而活跃用户达到18.6次。这种核心功能使用频次往往比登录频次更灵敏因为用户可能登录后只做了些边缘操作比如改头像、看公告这些动作对“用户是否还依赖平台”的证明力很弱。3.2 消费行为与付费能力分析消费行为是另一个重要维度但它不能单独看金额一定要结合消费频次、消费间隔、付费套餐变化来看。我当时做了三个单变量分析累计消费金额分布、近90天消费次数分布、最近一次消费距离今天的天数。累计消费金额呈现典型的幂律分布头部20%用户贡献了约70%的收入。这个规律本身符合预期但分组对比后发现一个更值得注意的现象累计消费金额高的用户并不等于低流失风险。我看了一下高价值用户累计消费超过1万元的流失率居然还是接近18%。这说明高消费用户流失的原因可能不是“付不起钱”而是“觉得不值得”。于是我把“近90天消费金额”除以“注册时长”计算了月度平均消费强度发现流失的高价值用户最近三个月的消费强度大幅下降下降幅度中位数超过60%。这个信号比累计消费金额本身更能预测流失。关于消费间隔我定义了一个简单但有效的特征消费间隔波动率。如果用户平均每20天消费一次但最近一次消费距今天数已经超过40天这是一个很直接的流失预警。我在EDA里就把“最近消费间隔 / 平均消费间隔”算出来画了分桶柱状图发现这个比值超过2的用户群体流失率迅速拉升到41%。后续建模中这个特征被证明是Top 3重要特征之一。3.3 客服交互与体验负面信号客服数据是很多人做流失分析时容易漏掉的维度。我让业务方把工单表、投诉表和退费记录做了关联生成了“近90天客服工单数”和“是否存在退款记录”两个特征。直觉上投诉多的人可能不满容易流失。但实际看分布时我发现一个反直觉现象有一小部分用户虽然发了很多工单但最后留下来了原因是问题被及时解决后用户对平台的信任反而增强了。这个现象提醒我不能只看客服交互次数还要看工单的状态和解决时效。所以在第二版探索中我增加了“平均工单响应时长”和“工单解决率”。分组对比显示流失用户最近90天平均客服响应时长是活跃用户的1.8倍而且流失用户中有过“未解决工单”的比例达到23%留存用户只有9%。这里的业务含义很明确过低的客服响应速度和未解决的负面体验是用户流失的加速器。处理这些数据时要特别注意时间字段的准确性。有些工单创建时间和结单时间不在同一个日期表格里需要先做时间对齐。我在“是否存在退款记录”上遇到过一个坑原始退款表里包含用户主动申请退款的记录也包括平台误操作的退款如果不加筛选就统计会高估“退款后流失”的概率。最终我只保留了“退款金额大于0且退款原因属于服务质量类”的记录这样才和业务方达成一致。4. 流失用户与留存用户对比分析4.1 分组对比的方法与可视化技巧EDA阶段最核心的动作就是“作对比”。我把样本分成两组流失组和留存组分别计算每个特征的均值、中位数和分位数。这里有一个容易出错的地方直接对原始特征求均值会受到极端值影响尤其是消费金额和登录次数这类长尾分布的数据。我建议先看中位数再看75分位数最后才看均值。例如“近30天登录次数”这个特征留存用户均值是22.5中位数是15流失用户均值是3.2中位数是1。两个组的中位数差异已经足够显著了。可视化方面我推荐使用双直方图来观察两个组的分布重叠程度。比如把“最近登录距今天数”按照流失组和留存组分别画出核密度曲线能看到留存组峰值在10天以内而流失组峰值集中在80到100天。如果两条曲线完全重叠说明该特征区分度极低。还可以用分位箱线图对比但要注意箱线图展示的是整体分布如果样本量差距很大箱体宽度会给人误导。我当时在分组对比时会对每个特征都计算一个简单的区分度指标|留存组中位数-流失组中位数| / 总体IQR。这个比值越大特征越值得保留。我整理了一张关键特征对比表算是给业务方看得最直观的产出特征留存组中位数流失组中位数差异方向近30天登录次数151流失组显著偏低近30天核心功能使用次数120.3流失组显著偏低最近消费距离今天数12天51天流失组更久未消费平均工单响应时长5.2小时9.6小时流失组体验更差注册时长240天310天流失组偏“老用户”这张表里的第五行很有意思注册时长更长的用户反而流失率更高说明这个平台面临的问题不是新用户留不住而是老用户在经历了新鲜感消退后慢慢离开。如果只看新用户留存就会漏掉这个核心危机。4.2 相关性矩阵与共线性排查做完分组对比后我开始算数值特征之间的相关性矩阵。这里用Pearson相关系数因为大部分特征经过变换后近似线性关系。热力图里最显著的是“近30天登录次数”和“近30天核心功能使用次数”的相关系数达到0.83说明两个特征高度冗余。后续建模时如果同时保留会造成多重共线性问题树模型里的特征重要性也会被分散。我的处理方法是先保留“核心功能使用次数”因为它在分组对比中的区分度更强同时衍生出“功能使用率”也就是“核心功能使用次数/登录次数”把两个原始信息融合成一个。相关分析也帮我发现了一些业务上合理的相关性累计消费金额和累计登录天数相关系数0.65说明长期活跃的用户确实更愿意付费客服工单数和退款记录相关系数0.47说明负面体验往往同时出现。这些相关性可以为后续特征工程提供组合思路。我还做了一步“目标变量相关性排序”把每个特征和流失标签的相关系数从高到低排列。排序结果中“最近消费距离今天数”和“最近登录距离今天数”与流失标签的正相关程度最高分别达到0.52和0.61。这两个字段本质上是“时间间隔”类特征几乎可以说是流失的直接度量。我在给业务方的报告里明确标注这类特征更适合做前端预警而不是因果分析。因为它们已经发生在“用户流失行为”的尾部阶段如果业务方想找到“为什么流失”还需要结合前面的行为特征深挖。5. 流失风险评分初探与特征衍生5.1 从EDA中提炼业务规则EDA的结果不能只是几张图和一堆表最好能转化为业务方可以直接理解和验证的规则。我在这个项目里提炼了三条核心规则。规则一如果用户近30天登录次数少于3次且核心功能使用次数为0那么流失概率超过60%。规则二如果用户最近一次消费距离今天超过45天同时累计工单数大于3那么流失概率接近50%。规则三如果用户平均消费间隔突然拉长1倍以上且没有新增工单那么该用户属于“静默流失预备期”需要触发召回。这些规则是如何得来的我借助了一个简单的事件树方法把所有样本按照某个特征的分位点切分成桶然后计算每个桶的流失率。比如把“近30天登录次数”分成0、1-3、4-7、8-14、15五个桶对应的流失率分别是68%、43%、22%、12%、6%。当两个特征同时分桶观察时流失率差异会更加明显。这些规则后续可以直接交给运营团队做短信推送或客服主动回访也可以作为机器学习模型的额外输入特征。需要注意的是规则里的阈值不能直接照搬其他行业或者网上教程必须基于自己的数据重新计算。比如“45天”这个阈值我是通过绘制“最近消费距离今天的天数”与流失率的关系曲线找出来的拐点。在那条曲线上30天之前流失率缓慢上升40到50天之间陡增超过60天后流失率趋平。这个拐点会随业务周期变化我建议每个季度复核一次。5.2 构建轻量级流失风险指数为了让业务方尽快用起来我没有等机器学习模型而是在EDA阶段就构建了一个轻量级流失风险指数。这个指数不依赖复杂算法只是把几个关键特征按照经验权重加权。具体做法是选取四个特征——近30天登录次数、最近消费距今的天数、近90天工单数、核心功能使用率。每个特征按分组规则打分0-5分得分越高代表风险越高。最后把四个分数相加得到0-20分的总指数。选择这四个特征的原因是它们在分组对比和相关性分析中都表现稳定而且业务含义清晰。权重我一开始设为1:1:1:1后来用一个稍微工程化的方式做了校准用每个特征单独和流失标签计算AUC然后按AUC的归一化值分配权重最终大约变成2.2 : 1.8 : 1.5 : 1。这里我不是追求最优只是希望指数有解释性且足够简单。校准后的指数在验证集上有不错的单调性指数小于6分的用户流失率只有5%指数在10到12分的用户流失率约为30%超过14分的用户流失率超过60%。这个风险指数的实用价值在于它能快速生成一份流失预警名单。运营同事拿到名单后可以按指数高低决定触达优先级而不是全量盲目做召回。它的另一层意义是帮我验证了后续建模的可行性如果一个简单的加权指数都能达到这种单调性说明数据里的信号是真实存在的正式训练机器学习模型时效果大概率不会太差。6. 踩坑记录与实操经验6.1 时间窗口设置的常见误区流失分析最大的坑就是时间窗口不干净。我第一次做的时候直接拿了用户全生命周期的数据来算特征结果把“用户已经流失之后的行为”也算进去了。比如用户在第30天不再登录但在第60天又因为活动登录了一下我统计“近90天登录次数”时把这个活动登录也算上了标签却仍是流失这就导致特征和标签互相矛盾。后来我改成严格分离观察窗口和标签窗口用第1天到第90天的数据构造特征用第91天到第180天是否活跃构造标签。这样才符合“预测未来流失”的业务逻辑。窗口长度也不是越长越好。我试过拉长观察窗口到180天特征稳定性是提高了但数据时效性下降很多用户的行为模式早已改变。对订阅制平台来说90天观察窗口和90天标签窗口是相对合理的起点。当然这个参数最好做敏感性分析比如同时跑60天和120天两版看结论是否稳定。6.2 样本不均衡问题的提前预判客户流失场景天然存在样本不平衡尤其是高客单价或者企业服务领域流失率可能只有5%左右。EDA阶段就要把这个比例算清楚否则后面建模时可能出现模型把所有样本都预测为“不流失”的情形。我当时的数据流失率是25%不算极端但分类阈值就不能随便定成0.5。在探索阶段我就把正负样本的分布可视化出来发现流失样本的特征分布方差更大这会导致模型倾向于忽略少数类。针对这个问题我在EDA阶段并没有急着做采样因为下采样会让流失率被人为抬高影响探索时的分组对比。正确的做法是先保留原始分布做分析在特征衍生结束后再考虑用SMOTE或代价敏感学习。另外评估指标也不要一上来就看准确率应该看AUC、召回率、精确率之间的权衡。我在给业务方的报告里明确建议召回率到80%的前提下再尽量提高精确率因为运营召回成本有限宁可贵一点也不能漏掉真正会流失的人。6.3 数据口径不一致的三类典型坑第一个坑是日期字段的格式不统一。登录行为表里的时间戳有的是字符串格式有的是datetime格式有的带时区有的不带。如果直接合并轻则报错重则由于时区差异把同一天的数据劈成两天。我的习惯是在读取后统一转成UTC时间戳再按业务需要的时区做转换。第二个坑是用户ID的生成逻辑变了。某个版本增加了“游客转注册”流程之后一部分用户ID前缀变化导致同一用户在不同时段出现两条不同ID的记录。如果没有在清洗阶段做ID映射特征聚合时会把一个用户拆成两个样本严重干扰生命周期分析。我后来用了一个间接方法通过设备号匹配一部分用户ID再在报告中注明“设备号关联仅作为辅助校验”。第三个坑是业务口径随活动变化。比如平台在第四季度推出“双倍积分”活动这段时间的消费行为高得异常。如果直接把所有历史数据混在一起探索很容易得出“用户消费能力大幅提升”的错误结论。正确的处理方式是增加一个“是否活动期间注册”或者“数据日期是否在活动期”的标记变量并在分组对比时区分活动期和非活动期。从这个项目里我个人体会最深的一点是客户流失判断不一定需要一开始就上复杂模型把探索性数据分析做到位很多结论就已经足够指导业务。所谓“分析功底”更多体现在对业务口径的敏感、对时间窗口的敬畏、对特征分布的理解上而不是炫技式地堆模型。后来我再接任何用户分析项目都习惯先把流失定义和样本分布弄清楚再决定后面用什么方法这个顺序一次都没变过。