机器学习模型预测不准?用Python手把手教你概率校准(附完整代码)

在金融风控、医疗诊断等关键领域,我们不仅需要模型给出分类结果,更希望了解预测结果的置信度。但你是否遇到过这种情况:模型预测某客户违约概率为80%,实际违约比例却只有50%?这种预测概率与真实发生频率的偏差,正是概率校准要解决的核心问题。

1. 概率校准的本质与价值

概率校准的本质是建立预测概率与真实发生频率之间的映射关系。想象一下天气预报:当气象台预测"降雨概率70%"时,我们期望在100次这样的预测中,实际降雨次数接近70次。机器学习模型的概率预测同样需要满足这种一致性。

为什么优秀模型也需要校准?

  • 逻辑回归等简单模型天生具有概率解释性
  • 但随机森林、XGBoost等复杂模型输出的"概率"实质上是类别比例
  • 即使原生支持概率输出的模型,在样本不平衡时也会出现偏差

实际案例:某银行信用卡审批系统使用随机森林模型,预测"高风险"客户中实际违约比例比预测值低15%,导致风险准备金严重高估。

校准后的概率在以下场景尤为重要:

  • 需要计算期望损失的风险评估
  • 多模型结果融合的集成系统
  • 成本敏感型决策的阈值选择

2. 校准效果评估方法论

2.1 可靠性图表(Reliability Diagram)

可靠性图表是直观展示校准效果的金标准。其绘制步骤包括:

  1. 将预测概率区间[0,1]分为10等份(0-0.1, 0.1-0.2,...,0.9-1.0)
  2. 计算每个区间内样本的:
    • 平均预测概率(x轴)
    • 实际正例比例(y轴)
  3. 绘制点线图并与对角线(y=x)对比
from sklearn.calibration import calibration_curve

prob_true, prob_pred = calibration_curve(y_test, y_proba, n_bins=10)
plt.plot(prob_pred, prob_true, marker='o', label='Our Model')
plt.plot([0, 1], [0, 1], linestyle='--', label='Perfectly Calibrated')

2.2 定量评估指标

除了可视化,我们还需要量化指标:

指标名称 计算公式 理想值
Brier Score $\frac{1}{N}\sum(y_i-p_i)^2$ 0
ECE $\sum|acc(b)-conf(b)|$ 0
Log Loss $-y\log(p)-(1-y)\log(1-p)$ 越小越好
from sklearn.metrics import brier_score_loss
print(f"Brier Score: {brier_score_loss(y_test, y_proba):.4f}")

3. 两大校准方法实战

3.1 Platt Scaling(Sigmoid校准)

适用于中小数据集(样本量<1000)的参数化方法:

from sklearn.calibration import CalibratedClassifierCV
from sklearn.svm import SVC

base_model = SVC(kernel='rbf')
platt_model = CalibratedClassifierCV(base_model, method='sigmoid', cv=3)
platt_model.fit(X_train, y_train)

# 获取校准后概率
calibrated_probs = platt_model.predict_proba(X_test)[:, 1]

关键参数解析:

  • cv=3:使用3折交叉验证防止过拟合
  • method='sigmoid':指定Platt校准方法
  • ensemble=True:是否使用多模型集成(默认True)

3.2 Isotonic回归校准

更适合大数据集的非参数方法,能学习任意单调映射:

isotonic_model = CalibratedClassifierCV(base_model, method='isotonic', cv=3)
isotonic_model.fit(X_train, y_train)

# 对比校准前后效果
print(f"原始模型Brier Score: {brier_score_loss(y_test, base_model.predict_proba(X_test)[:, 1]):.4f}")
print(f"Isotonic校准后: {brier_score_loss(y_test, isotonic_model.predict_proba(X_test)[:, 1]):.4f}")

方法对比指南:

特性 Platt Scaling Isotonic回归
数据需求 少量数据即可 需要大量数据
映射灵活性 固定sigmoid形式 任意单调函数
计算效率 较低
抗过拟合能力 需交叉验证

4. 完整项目实战:信用风险评估

让我们通过一个端到端案例演示完整流程:

4.1 数据准备与基线模型

import pandas as pd
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# 生成模拟信用数据
X, y = make_classification(n_samples=10000, n_features=20, 
                          n_informative=15, weights=[0.9, 0.1],
                          random_state=42)

# 划分训练/校准/测试集
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4)
X_cal, X_test, y_cal, y_test = train_test_split(X_temp, y_temp, test_size=0.5)

# 训练XGBoost基线模型
from xgboost import XGBClassifier
xgb = XGBClassifier(n_estimators=300, learning_rate=0.05)
xgb.fit(X_train, y_train)

4.2 校准实施与评估

# 定义校准函数
def evaluate_calibration(model, X, y, method='sigmoid'):
    calibrated = CalibratedClassifierCV(model, method=method, cv='prefit')
    calibrated.fit(X_cal, y_cal)
    probs = calibrated.predict_proba(X_test)[:, 1]
    
    # 绘制可靠性图
    prob_true, prob_pred = calibration_curve(y_test, probs, n_bins=10)
    plt.plot(prob_pred, prob_true, marker='o', label=f'{method}校准')
    
    # 计算指标
    brier = brier_score_loss(y_test, probs)
    print(f"{method}校准Brier Score: {brier:.5f}")
    return calibrated

# 对比不同方法
plt.figure(figsize=(10, 6))
plt.plot([0, 1], [0, 1], 'k--', label='理想校准')
evaluate_calibration(xgb, X_test, y_test, 'sigmoid')
evaluate_calibration(xgb, X_test, y_test, 'isotonic')
plt.legend()

4.3 业务应用示例

# 模拟业务决策:根据风险概率设置不同审批策略
def approval_strategy(prob, threshold=0.5):
    if prob < 0.3:
        return "自动通过"
    elif 0.3 <= prob < 0.7:
        return "人工审核"
    else:
        return "自动拒绝"

# 应用校准前后的差异示例
sample_idx = 10
raw_prob = xgb.predict_proba(X_test[sample_idx:sample_idx+1])[0, 1]
calibrated_prob = isotonic_model.predict_proba(X_test[sample_idx:sample_idx+1])[0, 1]

print(f"原始预测概率: {raw_prob:.2f} → 决策: {approval_strategy(raw_prob)}")
print(f"校准后概率: {calibrated_prob:.2f} → 决策: {approval_strategy(calibrated_prob)}")

5. 高级技巧与避坑指南

5.1 样本划分策略

校准需要独立的数据集,常见数据使用方式:

  1. 预划分法(推荐):

    • 原始训练集 → 训练基础模型
    • 独立校准集 → 训练校准器
    • 测试集 → 最终评估
  2. 交叉验证法

    CalibratedClassifierCV(base_estimator=model, 
                          method='isotonic', 
                          cv=5)
    

5.2 类别不平衡处理

当正负样本比例悬殊时:

  • 优先选择method='sigmoid'
  • 在校准前先进行类别平衡采样
  • 使用class_weight参数调整基础模型
xgb = XGBClassifier(scale_pos_weight=sum(y==0)/sum(y==1))

5.3 多分类问题校准

对于K类问题,有两种策略:

  1. One-vs-Rest(默认):

    • 对每个类别单独训练二分类校准器
    • 最后归一化概率总和
  2. 矩阵缩放(更复杂但更准确):

    from sklearn.calibration import CalibratedClassifierCV
    calibrated = CalibratedClassifierCV(base_model, 
                                      method='isotonic', 
                                      cv=5,
                                      ensemble=False)
    

在医疗诊断项目中,使用Isotonic校准将多分类模型的临床决策准确率提升了12%,避免了过度自信预测导致的误诊风险。

更多推荐