欢迎光临
我们一直在努力

SaaS 行业数据分析:AI 客户健康度评分与续费率预测模型

SaaS 行业数据分析:AI 客户健康度评分与续费率预测模型

行业场景与项目复盘 · 第4周 · 朱大喜的数据手记

做 SaaS 数据分析这一年,最让我感到"值了"的项目就是客户健康度评分体系。以前客服团队总是来问"这批客户会不会跑",我只能给一个模糊的趋势图。现在直接甩出一个 0-100 的健康度分数 + 续费概率值,决策效率直接拉满。今天就来复盘这套评分与预测模型是怎么搭起来的。

一、业务背景与问题定义

SaaS 行业的核心商业模式是订阅制,客户生命周期价值(LTV)取决于续费率。但传统方式靠客服"凭感觉"判断客户会不会续费,问题很明显:

  • 滞后性:客户都跑了一周了,才发现续费率下降
  • 主观偏差:不同客服对同一客户判断完全不同
  • 覆盖不足:只能关注头部客户,中小企业客户无人问津

我们要解决的核心问题:能否用数据提前量化每个客户的"健康程度",并预测续费概率?

# 业务指标定义
metrics = {
"续费率": "当期续费客户数 / 上期到期客户数",
"NDR": "(续费收入 + 升级收入 – 降级收入 – 流失收入) / 上期总收入",
"客户健康度": "综合评分 0-100,反映客户持续使用意愿",
"预警阈值": "健康度 < 40 为高风险,40-60 为中风险,> 60 为健康"
}

项目的业务目标是:提前 30 天识别高风险客户,将续费率从 78% 提升至 85% 以上。

二、数据准备与特征工程

客户健康度不是拍脑袋的,我们需要从多个维度提取特征。以下是我们最终使用的特征体系:

import pandas as pd
import numpy as np

# 加载多源数据
usage_df = pd.read_csv("customer_usage_2025.csv") # 产品使用数据
billing_df = pd.read_csv("customer_billing_2025.csv") # 账单与支付数据
support_df = pd.read_csv("customer_support_2025.csv") # 客服工单数据
nps_df = pd.read_csv("customer_nps_2025.csv") # NPS 调研数据

# 合并为统一客户视图
customer_master = usage_df.merge(billing_df, on="customer_id", how="left")
customer_master = customer_master.merge(support_df, on="customer_id", how="left")
customer_master = customer_master.merge(nps_df, on="customer_id", how="left")

# ===== 特征工程 =====

# 1. 使用活跃度特征
customer_master["login_freq_30d"] = customer_master["login_count_30d"] / 30 # 日均登录频次
customer_master["core_feature_usage"] = customer_master["core_action_count"] / customer_master["login_count_30d"] # 核心功能使用率
customer_master["usage_trend"] = customer_master["login_count_30d"] – customer_master["login_count_60d"] # 使用趋势(近30天-近60天)

# 2. 商务健康度特征
customer_master["payment_timeliness"] = (customer_master["on_time_payments"] / customer_master["total_payments"]) # 付款及时率
customer_master["arpu_change"] = customer_master["current_arpu"] – customer_master["previous_arpu"] # ARPU 变化
customer_master["contract_remaining"] = customer_master["contract_end_date"] – pd.Timestamp.now() # 合同剩余天数

# 3. 支持互动特征
customer_master["ticket_rate"] = customer_master["ticket_count"] / customer_master[" tenure_months"] # 月均工单率
customer_master["avg_resolution_hours"] = customer_master["avg_resolution_time"] # 平均解决时长
customer_master["escalation_rate"] = customer_master["escalation_count"] / customer_master["ticket_count"] # 升级率

# 4. 情感特征
customer_master["nps_score"] = customer_master["nps_score"].fillna(50) # 缺失NPS默认中性值

# 标记续费结果(标签)
customer_master["churn_label"] = (customer_master["renewed"] == 0).astype(int) # 1=流失, 0=续费

特征体系用 Mermaid 图更直观:

为什么使用趋势(近 30 天 – 近 60 天)比绝对值更有信号? 一个 HR SaaS 客户这个月登录 60 次、上个月 120 次,和另一个登录 40 次、上个月 15 次的客户比,前者的绝对值仍高于后者(60 > 40)。但如果只看绝对值做分类,模型会把前者判为"安全"客户——而实际上他的使用量已经腰斩。趋势特征捕捉的是行为的加速度:它是上升还是下降,下降了多少。在流失预测场景下,"正在变差"的信号强度通常远高于"当前状态有多好",因为 SaaS 流失是一个渐进过程——客户不是某一天突然决定"我不续了",而是连续 4-6 周使用量缓慢下降。趋势比绝对值更能捕捉这个斜坡。

三、AI 模型构建与训练

我们采用双模型架构:健康度评分用加权评分卡模型,续费预测用 XGBoost 分类模型。评分卡适合解释性要求高的业务场景,XGBoost 适合精准预测。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import xgboost as xgb
from sklearn.metrics import roc_auc_score, classification_report

# ===== 模型1:加权评分卡 =====
# 各维度权重由业务方和数据团队共同确定
weight_config = {
"usage_weight": 0.35, # 使用活跃度权重最高
"billing_weight": 0.25, # 商务健康度次之
"support_weight": 0.20, # 支持互动
"nps_weight": 0.20 # 情感
}

def calculate_health_score(row, weights):
"""计算客户健康度评分(0-100)"""
# 各维度子评分(归一化到0-100)
usage_score = min(100, row["login_freq_30d"] * 50 + row["core_feature_usage"] * 50)
# 使用趋势加分或扣分
if row["usage_trend"] > 0:
usage_score = min(100, usage_score + 10)
else:
usage_score = max(0, usage_score – 15)

billing_score = row["payment_timeliness"] * 80 + min(20, row["arpu_change"] * 10)
# 支持维度:工单少=好,解决快=好,升级少=好
support_score = max(0, 100 – row["ticket_rate"] * 30 – row["escalation_rate"] * 40 – row["avg_resolution_hours"] * 2)
nps_score = row["nps_score"] # NPS本身就是0-10,映射到0-100

# 加权求和
total = (
usage_score * weights["usage_weight"] +
billing_score * weights["billing_weight"] +
support_score * weights["support_weight"] +
nps_score * weights["nps_weight"]
)
return round(total, 1)

# 应用评分函数
customer_master["health_score"] = customer_master.apply(
lambda row: calculate_health_score(row, weight_config), axis=1
)

# ===== 模型2:XGBoost 续费预测 =====
feature_cols = [
"login_freq_30d", "core_feature_usage", "usage_trend",
"payment_timeliness", "arpu_change", "contract_remaining",
"ticket_rate", "avg_resolution_hours", "escalation_rate",
"nps_score", "health_score" # 评分卡结果也作为特征输入
]

X = customer_master[feature_cols]
y = customer_master["churn_label"]

# 训练集/测试集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# 特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# XGBoost 模型训练
xgb_model = xgb.XGBClassifier(
n_estimators=200,
max_depth=5,
learning_rate=0.1,
subsample=0.8,
colsample_bytree=0.8,
objective="binary:logistic",
eval_metric="auc",
random_state=42
)
xgb_model.fit(X_train_scaled, y_train)

# 模型评估
y_pred_proba = xgb_model.predict_proba(X_test_scaled)[:, 1]
auc_score = roc_auc_score(y_test, y_pred_proba)
print(f"AUC: {auc_score:.4f}")
# 输出: AUC: 0.8923

# 续费概率 = 1 – 流失概率
customer_master["renewal_probability"] = 1 – xgb_model.predict_proba(scaler.transform(X))[:, 1]

模型架构整体流程如下:

四、业务落地与效果评估

为什么评分卡和 XGBoost 不是替代关系而是互补关系? 很多人觉得"都有了 XGBoost 还要评分卡干嘛",但这是把"预测"和"解释"混为一谈。XGBoost 给你续费概率 0.23,客户经理问"为什么是 0.23 而不是 0.8?",你能回答"树的第 5 次分裂用了 login_freq_30d ≤ 2.3",客户经理完全听不懂。评分卡告诉你"使用活跃度 35 分 + 商务健康度 20 分 = 55 分",每个维度可追溯、可干预。更关键的是,评分卡的干预方向是明确的:使用分低了就推培训,商务分低了就推客户成功经理。XGBoost 只是告诉你"这个人要跑",评分卡告诉你"他跑的原因可能是什么"。

模型上线后,我们做了三层落地机制:

# ===== 自动化预警机制 =====
import schedule
import time

def daily_health_check():
"""每日健康度检查与预警推送"""
# 重新计算评分和概率
current_scores = customer_master[["customer_id", "health_score", "renewal_probability"]].copy()

# 风险分级
current_scores["risk_level"] = current_scores.apply(
lambda row: "高风险" if row["health_score"] < 40 and row["renewal_probability"] < 0.5
else ("中风险" if row["health_score"] < 60 or row["renewal_probability"] < 0.7
else "健康"), axis=1
)

# 筛选高风险客户推送给客服团队
high_risk = current_scores[current_scores["risk_level"] == "高风险"]
mid_risk = current_scores[current_scores["risk_level"] == "中风险"]

# 推送消息(实际接入企业微信/钉钉)
print(f"今日高风险客户: {len(high_risk)} 家")
print(f"今日中风险客户: {len(mid_risk)} 家")

# 生成干预建议
for cid in high_risk["customer_id"].head(10):
row = customer_master[customer_master["customer_id"] == cid].iloc[0]
if row["usage_trend"] < 0:
print(f"客户 {cid}: 使用频次下降,建议产品培训介入")
elif row["payment_timeliness"] < 0.7:
print(f"客户 {cid}: 付款延迟,建议商务沟通")
elif row["escalation_rate"] > 0.3:
print(f"客户 {cid}: 工单升级率高,建议技术支持重点跟进")

# 每天早上 9 点执行
schedule.every().day.at("09:00").do(daily_health_check)

上线三个月后的核心效果:

指标上线前上线后变化
续费率 78% 84.5% +6.5%
高风险客户识别提前量 0天 平均21天 +21天
客服干预成功率 32% 58% +26%
NDR 95% 102% +7%

五、总结

🚨 踩坑提醒

  • NPS 缺失值用均值填充会掩盖满意度分化:fillna(50) 把没填 NPS 的用户都设为中性——但真实的"未填写用户"往往是两类极端:满意到懒得填 vs 不满到不想填。用 50 填充会让模型认为这些客户"一般满意",实际上第 2 类客户的流失率远高于均值。建议分析"未填写"群体的特征,如果他们的流失率显著不同于 50 分对应的群体,应该单独设一个缺失标记列。

  • XGBoost 的特征重要性不等于业务因果:core_feature_usage 的 feature importance 最高(0.25),不代表"提升核心功能使用率就能降低流失"。可能的情况是:本身就很忠诚的客户才会高频使用核心功能,而不是高频使用导致了忠诚。因果关系的验证需要做 A/B 测试——给一批用户推送核心功能引导,看后续续费率是否提升。

  • 评分卡权重由数据驱动但 NPS 覆盖率太低时权重会失真:初期用相关性定权,NPS 权重被推到 0.4。但只有 35% 客户有 NPS 数据,剩下 65% 是填充值。一个三分之二靠填充的特征占 40% 的权重,等于评分体系被"猜"的数据主导。建议对低覆盖率的特征设置权重上限(如覆盖率 <50% 的特征最高权重不超过 0.15),或者对缺失样本单独计算评分。

  • 复盘这个项目,三个关键经验值得记住:

  • 评分卡和机器学习不是对立的——评分卡提供可解释的业务评分,XGBoost 提供精准的概率预测,两者结合比单用任何一个效果都好。健康度评分作为特征输入 XGBoost 后,AUC 提升了 0.05。

  • 特征工程比模型选择更重要——我们花了 60% 的时间在特征定义和数据对齐上。特别是"使用趋势"这个特征(近30天 vs 近60天的变化量),单特征 AUC 就有 0.65,比很多复杂模型都强。

  • 落地机制决定 ROI——模型做出来只是第一步,真正的价值在于每日预警 + 干预建议 + 客服闭环。没有这三层,模型就是摆设。

  • 踩过的坑也有:初期评分卡权重纯靠数据相关性定,结果 NPS 权重过高(0.4),但 NPS 调研覆盖率只有 35%,大量缺失值导致评分失真。后来降到 0.20,缺失用中性值填充,反而更稳定。

    下一步计划:引入客户行为序列特征(用 LSTM 编码近 90 天的操作序列),尝试捕捉更细微的使用模式变化。到时候再来和大家分享进展!

    赞(0)
    未经允许不得转载:171主机测评 » SaaS 行业数据分析:AI 客户健康度评分与续费率预测模型
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址