逻辑回归 5 层实战 · German Credit + Telco Churn

D+18 教程 2026-08-24 ~3800 字 面向数据科学家 100% 本机真实运行
逻辑回归 = 金融场景的"白月光"。本文是"商业分析四大算法"系列的第 3 篇,跑两个真实数据集:UCI German Credit (1000 笔贷款) + IBM Telco Churn (7032 客户,跟 Churn essay 联动)。5 层结构 + WOE 分箱 + 评分卡 + PSI 监控。
5 层结构: L1 数学直觉 → L2 WOE 分箱 → L3 LR 训练 → L4 评分卡 → L5 PSI 监控

L1数学直觉

P(y=1|x) = 1 / (1 + e^(-z))    (sigmoid)
z = w·x + b                    (线性组合)

训练: 最大化对数似然
L = Σ [y·log(p) + (1-y)·log(1-p)]

L1 正则: 加 Σ|w| → 系数稀疏 (特征选择)
L2 正则: 加 Σw² → 系数小 (防过拟合)

优势: 可解释 (系数 = log-odds), 合规友好

L2WOE 分箱

WOE (Weight of Evidence) = 把类别/数值特征转成"对好坏客户的预测力"分数。

def calculate_woe_iv(df, col, target):
    grouped = df.groupby(col)[target].agg(['count', 'sum', 'mean'])
    grouped['bad_dist'] = grouped['sum'] / grouped['sum'].sum()
    grouped['good_dist'] = (grouped['count'] - grouped['sum']) / (grouped['count'] - grouped['sum']).sum()
    grouped['woe'] = np.log(grouped['good_dist'] / grouped['bad_dist'])
    grouped['iv'] = (grouped['good_dist'] - grouped['bad_dist']) * grouped['woe']
    return grouped

IV 越大,特征预测力越强 (IV > 0.5 强, 0.3-0.5 中, < 0.1 弱)。

German Credit Top IV 特征

Top 10 高 IV: credit_amount: 14.46 (极强) duration: 0.73 checking_status: 0.67 age: 0.45 credit_history: 0.29 savings_status: 0.20 purpose: 0.17 property_magnitude: 0.11 employment: 0.09 housing: 0.08

Telco Churn Top IV 特征

Top 10: TotalCharges: 10.75 (极强) MonthlyCharges: 3.36 Contract: 1.23 tenure: 0.92 OnlineSecurity: 0.72 TechSupport: 0.70 InternetService: 0.62 OnlineBackup: 0.53 DeviceProtection:0.50 PaymentMethod: 0.46

L3LR 训练 + 6 指标

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(
    penalty="l1", C=0.5, solver="saga",
    class_weight="balanced",  # 处理不平衡
    max_iter=2000, random_state=42
)
lr.fit(X_train_woe, y_train)

6 指标对比

数据集AUCKSPR-AUCPrecisionRecallF1
German Credit0.77840.43330.59630.51220.70000.5915
Telco Churn (WOE)0.99900.97070.99730.94540.98750.9660
LR ROC 曲线
L3-L4 · German Credit + Telco Churn ROC 曲线 + 评分卡 vs 坏率
诚实发现: Telco WOE AUC = 0.999 看似完美,但**实际是过拟合**。WOE 转换把每个类别变成一个值,L1 + class_weight 在测试集上几乎完美记住。这是因为我没做交叉验证,直接 fit_transform 再 split,数据泄露。真实业务应该用 sklearn.pipeline + cross_val_score。**AUC 0.84-0.88 才是 Telco 的真实水平**(Churn essay 跑过的)。

L4评分卡 (Scorecard)

把 LR 概率转成可解释的分数 (300-850 标准分):

score = 600 + (woe_value × coef) × 50
# 评分越高,客户越好
# 评分 → 坏率:
# 300-400: 60% 坏客户
# 500-600: 30%
# 700-850: < 10%

German Credit 评分卡验证

评分分布: min=2, max=92, mean=44 评分区间 vs 坏率: 2-18: 坏率 5.0% (n=60) 18-34: 坏率 15.0% (n=60) 34-51: 坏率 26.7% (n=60) 51-68: 坏率 40.0% (n=60) 68-92: 坏率 63.3% (n=60) → 评分单调递增,完美分离
评分卡工程价值:

L5PSI 监控 (线上漂移)

PSI (Population Stability Index) = 训练数据 vs 上线数据的概率分布漂移。

def calculate_psi(expected, actual, bins=10):
    edges = np.linspace(min(expected.min(), actual.min()),
                       max(expected.max(), actual.max()), bins + 1)
    e_pct = np.histogram(expected, bins=edges)[0] / len(expected)
    a_pct = np.histogram(actual, bins=edges)[0] / len(actual)
    psi = sum((a - e) * np.log(a / e) for e, a in zip(e_pct, a_pct))
    return psi

psi = calculate_psi(train_pred, test_pred)

PSI 阈值

PSI 值状态动作
< 0.1稳定继续监控
0.1 - 0.25轻微漂移观察 + 增加监控频率
> 0.25严重漂移必须重训模型
PSI (German→Telco): 5.55 (不同数据集当然差异大) PSI (10% 漂移模拟): 2.44 (远超 0.25 阈值 → 重训)
线上监控实战:

与 Churn essay 联动

模型特征工程Telco AUC备注
Churn essay LR (M1)One-hot + 34 维0.8409合理 baseline
本篇 LR (OneHot)One-hot + 1055 维 (German)0.7784 (German)数据集切换
本篇 LR (WOE)WOE 编码0.999 (过拟合)需 CV 验证

反复论证结论: WOE 编码在 LR 上有强预测力但容易过拟合,需要严格 CV。生产环境推荐 **Pipeline + cross_val_score**,而不是 fit_transform + split。


与前文 essay 联动

完 · 2026-08-24 · Chase's Personal Page · 100% 本机真实运行