使用Scikit-learn包的CalibratedClassifierCV
CalibratedClassifierCV 用于校准分类器的预测概率。许多分类器(如 SVM、决策树、随机森林)的 predict_proba 输出的概率并不准确,该类通过交叉验证来校准这些概率。
核心概念
概念 │ 说明
──────────┼──────────────────────────────────────────────────────────────────────
校准方法 │ sigmoid(Platt 缩放,适合小样本)或 isotonic(保序回归,适合大样本)
──────────┼──────────────────────────────────────────────────────────────────────
交叉验证 │ 内部用 CV 防止过拟合,避免用训练数据校准自身
──────────┼──────────────────────────────────────────────────────────────────────
包装器 │ 包裹任意实现了 fit / predict_proba 的分类器
基本用法
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.calibration import CalibratedClassifierCV
from sklearn.metrics import brier_score_loss
# 1. 生成数据
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. 基础分类器(SVC 默认不支持 predict_proba,概率未校准)
base_clf = SVC(kernel='rbf')
# 3. 用 CalibratedClassifierCV 包装
# method='sigmoid' -> Platt scaling
# cv=5 -> 5 折交叉验证
calibrated_clf = CalibratedClassifierCV(base_clf, method='sigmoid', cv=5)
calibrated_clf.fit(X_train, y_train)
# 4. 校准后的概率
proba = calibrated_clf.predict_proba(X_test)
print("校准后 Brier score:", brier_score_loss(y_test, proba[:, 1]))
对比校准前后效果
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.calibration import calibration_curve
# 用朴素贝叶斯做对比(其概率通常校准较差)
clf = GaussianNB()
clf.fit(X_train, y_train)
proba_uncalibrated = clf.predict_proba(X_test)[:, 1]
calibrated = CalibratedClassifierCV(clf, method='isotonic', cv=5)
calibrated.fit(X_train, y_train)
proba_calibrated = calibrated.predict_proba(X_test)[:, 1]
# 绘制校准曲线
fig, ax = plt.subplots(1, 1, figsize=(6, 6))
for name, proba in [('未校准', proba_uncalibrated), ('校准后', proba_calibrated)]:
frac_pos, mean_pred = calibration_curve(y_test, proba, n_bins=10)
ax.plot(mean_pred, frac_pos, marker='o', label=name)
ax.plot([0, 1], [0, 1], 'k--', label='完美校准')
ax.set_xlabel('平均预测概率')
ax.set_ylabel('实际正样本比例')
ax.set_title('校准曲线 (Calibration Curve)')
ax.legend()
plt.tight_layout()
plt.savefig('calibration_curve.png', dpi=150)
plt.show()
# Brier score 对比
print("未校准 Brier:", brier_score_loss(y_test, proba_uncalibrated))
print("校准后 Brier:", brier_score_loss(y_test, proba_calibrated))
两种校准方法对比
from sklearn.ensemble import RandomForestClassifier
base = RandomForestClassifier(n_estimators=100, random_state=42)
for method in ['sigmoid', 'isotonic']:
cal = CalibratedClassifierCV(base, method=method, cv=5)
cal.fit(X_train, y_train)
p = cal.predict_proba(X_test)[:, 1]
print(f"method={method:10s} Brier={brier_score_loss(y_test, p):.4f}")
关键参数说明
CalibratedClassifierCV(
estimator=None, # 基础分类器(旧版叫 base_estimator)
method='sigmoid', # 'sigmoid' 或 'isotonic'
cv=5, # 交叉验证折数;设为 'prefit' 表示模型已训练好
n_jobs=None, # 并行数
)
cv=‘prefit’ 模式(模型已训练好)
# 先单独训练模型
base_clf = SVC(kernel='rbf', probability=True)
base_clf.fit(X_train, y_train)
# 再用一个独立的校准数据集来校准
X_calib, y_calib = X_test[:100], y_test[:100] # 校准集
X_eval, y_eval = X_test[100:], y_test[100:] # 评估集
calibrated = CalibratedClassifierCV(base_clf, cv='prefit')
calibrated.fit(X_calib, y_calib) # 仅做校准,不重新训练
proba = calibrated.predict_proba(X_eval)
print("prefit Brier:", brier_score_loss(y_eval, proba[:, 1]))
选择建议
场景 │ 推荐配置
────────────────────────┼─────────────────────────────────────────
样本量 < 1000 │ method=‘sigmoid’(参数少,不易过拟合)
────────────────────────┼─────────────────────────────────────────
样本量 ≥ 1000 │ method=‘isotonic’(更灵活,校准更精确)
────────────────────────┼─────────────────────────────────────────
模型已训练好,仅需校准 │ cv=‘prefit’ + 独立校准集
────────────────────────┼─────────────────────────────────────────
需要并行加速 │ n_jobs=-1
│ 注意:校准只改善概率估计的质量(Brier score、log loss),不一定提升分类准确率(accuracy)。如果你的下游任务依赖概率值(如设置阈值、排序、风险评估),校准就非常有价值。
- 点赞
- 收藏
- 关注作者
评论(0)