当前位置: 首页 > news >正文

客户流失预警中uplift建模案例、入门学习(二)

本文【Stop Guessing What Works — How I’d Use Uplift Modelling to Target Churn Interventions without fancy AI】介绍了如何通过提升建模(Uplift Analysis)来优化客户流失干预策略,重点在于针对“可被说服者”进行干预,而非浪费预算在“确定会留下”或“无可挽回”的客户上。文章详细阐述了提升分析的概念、实施方法,以及如何将结果转化为实际行动。、计算大致过程:

  • 提升模型的实现包括训练两个独立模型(一个针对接受干预客户,另一个针对未接受干预客户),并计算两者的差值。
  • 根据提升分数和流失风险,将客户划分为不同的行动建议:干预、跳过、避免或测试。

两篇非常简单的流失预警预测模型案例:
客户流失预警的倾向分类建模案例(一)
在客户流失预警中使用uplift模型(二)


文章目录

  • 1 前言
    • 1.1 什么是uplift分析
    • 1.2 为什么提升模型比单纯的倾向模型更有意义
  • 2 案例
    • 2.1 重复使用流失数据集(并稍微扩展它)
    • 2.2 添加处理标志
    • 2.3 两个小型模型(经典 + 可解释)
    • 2.4 将得分转化为行动(四个细分市场)
    • 2.5 “这能赚钱吗?”
    • 2.6 uplift的含义
  • 3 实用注意事项
  • 4 结论


1 前言

1.1 什么是uplift分析

提升分析衡量的是干预措施的因果影响。基本上,我们不再问“谁会流失?”,而是问“因为我们进行了干预,我们能挽救谁?”

为什么提升分析很重要: 假设你的流失模型标记了100个“高风险”客户,你对他们全部进行折扣轰炸,那么很有可能你会把预算浪费在许多无论如何都会留下来的客户身上。此外,你也很可能会错过那些只有在你实际帮助他们时才会留下的客户。

在提升分析中,特别是针对我上一篇文章中的银行场景,我们将这些客户类别分为四个通俗易懂的细分市场:

  • 可挽留者(Persuadables):如果我们不采取任何措施就会流失(在我们的案例中是离开银行),但如果我们介入就会留下来。(最佳目标
  • 必然留存者(Sure Things):无论如何都会留下来。(无需在此花费任何预算
  • 已流失者(Lost Causes):无论采取何种处理措施都会流失。(承认并继续前进
  • 沉睡者(Sleeping Dogs):本来会留下来,但干预措施反而让他们离开。我有时觉得我就是一些公用事业提供商的“沉睡的狗”。我总是在等待触发点来放弃他们。基本上,他们联系我,我就会“想起”我与他们不愉快的经历,然后自然而然地离开。他们似乎也知道这一点,因为目前还没有“烦人”的交易找上门来。

这种框架可以防止“一刀切的优惠”,并真正将预算集中在能够改变结果的地方。

1.2 为什么提升模型比单纯的倾向模型更有意义

通常,倾向得分会说:“客户A有80%的流失(离开)可能性。”我承认这很有帮助,但也不完整。它通常不会说明短信、费用减免、电子邮件或电话是否可能改变这一结果

因此,提升模型捕捉的是以下两者之间的差异:

  1. 如果进行处理(发送短信、电子邮件或应用忠诚度积分)的流失概率
  2. 如果未进行处理(不采取任何措施)的流失概率

这个差异就是提升得分(uplift score)。结论将是这样的:

  • 正向提升 → 处理有帮助(值得目标)。
  • 负向提升 → 处理有害(避免!)。

2 案例

2.1 重复使用流失数据集(并稍微扩展它)

我模拟了一个相对真实的零售银行数据集,其中包含人口统计、数字参与度、余额、贷款等特征。为了简化,我将通过添加一个处理(treatment) 标志来扩展相同的CSV,该标志代表一个挽留优惠(例如,费用减免、忠诚度奖金、分行电话)。

在现实生活中,你会在一个小规模试点中随机分配谁获得优惠。随机化使提升测量诚实且简单。

我将在这里添加一些必要的代码片段,供你运行和复制附加列以及提升计算。我将保持代码简洁易读。像往常一样,包含更详细步骤的完整笔记本在我的GitHub上。

2.2 添加处理标志

假设数据集与运行此处的main.py代码时生成的数据集相同,那么我们将模拟一个50/50随机优惠和一个轻微的“有帮助”效果,仅用于说明目的。这在实际场景中会根据不同的业务需求而有所不同。因此,请勿将此方法用于实际生产数据。

import numpy as np  
import pandas as pddf = pd.read_csv("equity_bank_churn_dataset.csv")  
np.random.seed(42)df["treatment"] = np.random.binomial(1, 0.5, len(df))df["churn_probability"] = pd.to_numeric(df["churn_probability"], errors="coerce").fillna(0.0)  
TREATMENT_EFFECT = -0.10    
df["adj_churn_prob"] = (df["churn_probability"] + TREATMENT_EFFECT * df["treatment"]).clip(0, 1)df["churned_treated"] = np.random.binomial(1, df["adj_churn_prob"]).astype(int)label_col = "churned" if "churned" in df.columns else "churn"  
df["outcome"] = np.where(df["treatment"]==1, df["churned_treated"], df[label_col]).astype(int)

⚠ 请勿在生产环境中伪造结果。运行一个小的随机试点,这样你的处理组与对照组结果才是真实的。

2.3 两个小型模型(经典 + 可解释)

计算uplift 涉及训练一个模型来预测处理组客户的流失,以及另一个模型来预测对照组客户的流失。
然后,对每个人进行这两种情况的预测,差异就是提升。听起来很简单,这就是提升分析的全部思想。下面的代码片段有助于说明这一点:

from sklearn.compose import ColumnTransformer  
from sklearn.impute import SimpleImputer  
from sklearn.preprocessing import OneHotEncoder, StandardScaler  
from sklearn.pipeline import Pipeline  
from sklearn.linear_model import LogisticRegressionDROP = {"customer_id","account_open_date","churn_date",  "churn_probability","churned","churn","churn_flag",  "treatment","adj_churn_prob","churned_treated","outcome"}cat_cols, num_cols = [], []  
for c in df.columns:  if c in DROP:   continue  (cat_cols if df[c].dtype=="object" else num_cols).append(c)pre = ColumnTransformer([  ("cat", Pipeline([("imp", SimpleImputer(strategy="most_frequent")),  ("ohe", OneHotEncoder(handle_unknown="ignore", sparse_output=False))]), cat_cols),  ("num", Pipeline([("imp", SimpleImputer(strategy="median")),  ("sc", StandardScaler())]), num_cols),  
])df_treat = df[df["treatment"]==1].copy()  
df_ctrl  = df[df["treatment"]==0].copy()X_treat, y_treat = df_treat[cat_cols+num_cols], df_treat["outcome"]  
X_ctrl,  y_ctrl  = df_ctrl[cat_cols+num_cols],  df_ctrl["outcome"]m_treat = Pipeline([("pre", pre), ("clf", LogisticRegression(max_iter=1000, class_weight="balanced"))]).fit(X_treat, y_treat)  
m_ctrl  = Pipeline([("pre", pre), ("clf", LogisticRegression(max_iter=1000, class_weight="balanced"))]).fit(X_ctrl,  y_ctrl)X_all = df[cat_cols+num_cols]  
df["p_treat"] = m_treat.predict_proba(X_all)[:,1]     
df["p_ctrl"]  = m_ctrl.predict_proba(X_all)[:,1]      
df["uplift"]  = df["p_ctrl"] - df["p_treat"]        

这是核心:$uplift = p(no-treat) - p(treat)$

更高的提升 → 介入带来的预期收益越大。

2.4 将得分转化为行动(四个细分市场)

我们将通过简单、可解释的规则将客户进行分类,这些规则当然可以根据你的预算和风险承受能力进行调整,阈值也可以更改。

up_pos = df["uplift"].quantile(0.70)     
up_neg = df["uplift"].quantile(0.10)     
r_hi   = df["p_ctrl"].quantile(0.60)     
r_lo   = df["p_ctrl"].quantile(0.20)   def segment(u, r):  if u <= up_neg: return "Sleeping Dog"            if (u >= up_pos) and (r >= r_hi): return "Persuadable"  if (r <= r_lo) and (up_neg < u < up_pos): return "Sure Thing"  if (r >= r_hi) and (up_neg < u < up_pos): return "Lost Cause"  return "Gray Zone" df["segment"] = [segment(u, r) for u, r in zip(df["uplift"], df["p_ctrl"])]df["action"] = df["segment"].map({  "Persuadable": "Target (intervene)",  "Sure Thing": "Do not treat",  "Lost Cause": "Do not treat (low ROI)",  "Sleeping Dog": "Avoid (may backfire)",  "Gray Zone": "Test small / learn"  
})

作为产品负责人,我知道你们中的一些人会这样解读:

  • 优先处理可挽留者(钱花得值)。
  • 跳过必然留存者(他们反正会留下)。
  • 跳过已流失者(难以挽回)。
  • 排除沉睡的狗(不要惹麻烦!)。
  • 灰色区域——进行小规模测试并从其行为中学习。然后你可以决定如何处理他们。

2.5 “这能赚钱吗?”

这是业务部门很可能会问你的一个基本问题。我会这样回答:如果平均客户生命周期价值(CLV)CLVCLVCLV,并且每次处理的成本COSTCOSTCOST,那么预期利润可以表述为:

Profiti≈uplifti×CLV−COST\text{Profit}_i \approx \text{uplift}_i \times \text{CLV} - \text{COST} Profitiuplifti×CLVCOST

2.6 uplift的含义

  • uplifti\text{uplift}_iuplifti:客户 iii 如果得到处理,流失概率的估计下降值(例如,Pctrl−PtreatP_{\text{ctrl}} - P_{\text{treat}}PctrlPtreat)。这将是一个介于0和1之间的数字。
  • CLV:通过留住客户所获得的净客户生命周期价值(金钱)。这可以根据具体业务情况有不同的定义。
  • COST:每次干预(短信、电话、折扣、电子邮件等)的单客户成本

因为 uplifti\text{uplift}_iuplifti 是一个概率,所以 uplifti×CLV\text{uplift}_i \times \text{CLV}uplifti×CLV 是挽救该客户的预期货币价值。这个乘积减去COST就是留住客户的预期利润

  • 如果 Profiti>0\text{Profit}_i > 0Profiti>0,那么值得进行处理。
  • 如果 Profiti<0\text{Profit}_i < 0Profiti<0,那么就没有必要保留他们进行处理。

我将在这里举一个例子来说明:

假设 Uplifti=0.25\text{Uplift}_i = 0.25Uplifti=0.25CLV=250\text{CLV}=250CLV=250 , 成本是 555,那么:

Profiti≈(0.25×250)−5=57.5\text{Profit}_i \approx (0.25 \times 250) - 5 = 57.5 Profiti(0.25×250)5=57.5

因此,平均而言,处理这位客户可能会带来 $57.5 的利润。我已经为所有有利润的客户设定了处理阈值。根据你的预算,你可以改变这一点,例如,只针对那些可能带来更高利润的客户。

下面的代码说明了这一点。只需根据这个数字选择排名靠前的客户,直到达到你的预算。

CLV, COST, BUDGET = 250.0, 5.0, 5000  df["expected_profit"] = df["uplift"] * CLV - COST  
campaign = df.sort_values("expected_profit", ascending=False).head(BUDGET)print("Selected:", len(campaign), "Expected total profit ~", int(campaign["expected_profit"].sum()))  
campaign[["customer_id","uplift","p_ctrl","p_treat","segment","action","expected_profit"]].head(10)

这在很大程度上使得决策“诚实”,即在增量收益超过成本的情况下提供处理。

3 实用注意事项

  • 尽可能随机化。即使是一个小规模的A/B试点(例如,10%的保留组)也会使你的提升估计更加可靠。
  • 谨慎对待非随机处理。 如果团队手动选择要联系的客户,那么你的数据就会被所有定义所偏置。在这种情况下,考虑因果ML或进行干净的实验。
  • 非常清楚地定义“流失”,因为它非常棘手。 在银行业中,它可能是账户关闭、90天不活跃或余额接近零。有些客户会流失多次,因此要考虑是否最好留住他们。简而言之,你的标签决定了行为。
  • 关注沉睡的狗。 激进的“挽留”活动可能会引起投诉和退订。正如我之前提到的,我就是一些公用事业提供商的这类客户。
  • 保持实验的可解释性。 从经典模型开始有助于获得业务认可。你以后总可以升级到更高级的元学习器(T-learner、X-learner、因果森林)。

4 结论

提升分析弥合了预测干预之间的鸿沟。通过一个小型、经典的设置,你可以根据增量影响对客户进行排名,将他们细分为可挽留者/必然留存者/已流失者/沉睡的狗,并将你的预算花在真正能产生效果的地方。像往常一样,我的完整代码在这里

http://www.dtcms.com/a/389349.html

相关文章:

  • SSH远程管理工具
  • 4644电源芯片的介绍和使用
  • MIPI D-PHY布线规则
  • 《深入理解Java虚拟机》第四章节读书笔记:虚拟机性能监控、故障处理工具
  • ​​[硬件电路-251]:电源相关常见的专业术语
  • 日志中的SQL语句直接转为可执行的SQL
  • Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践
  • Nginx-RTMP-Module开源项目全解析:从基础部署到企业级应用实践
  • 新代系统如何输入期限密码
  • 【C++】STL--stack(栈)queue(队列)使用及其重要接口模拟实现
  • 计算机组成原理:奔腾系列机的虚存组织
  • 架构模式的双雄会:Reactor与Proactor的高并发哲学
  • 【C++】STL详解(八)—stack和queue的模拟实现
  • 【LeetCode Hot100----08-二叉树篇中(06-10),包含多种方法,详细思路与代码,让你一篇文章看懂所有!】
  • ARM(12) - ADC 检测光照强度
  • 网格生成引擎:设计原则、关键组件
  • 【开发AI】Spring AI Alibaba:集成AI应用的Java项目实战
  • Spark专题-第二部分:Spark SQL 入门(2)-算子介绍-Scan/Filter/Project
  • Selenium 自动化爬虫:处理动态电商页面
  • 无需Selenium:巧用Python捕获携程机票Ajax请求并解析JSON数据
  • Python版Kafka基础班 - 学习笔记
  • IDEA 查看 Maven 依赖树与解决 Jar 包冲突
  • 【LVS入门宝典】LVS与Nginx、HAProxy的对比:四层(LVS) vs 七层(Nginx)的适用场景
  • 系统安全配置与加固
  • 【AI-Agent】AI游戏库
  • 病毒库更新原理
  • 服务器内存爆炸,日志无报错,通过分析 Dump 文件查找问题原因
  • 【Redis学习】服务端高并发分布式结构演变之路
  • 【JavaScript 性能优化实战】第三篇:内存泄漏排查与根治方案
  • 关于JavaScript性能优化实战的技术