当你在Kaggle上第一次用Scikit-learn跑通Titanic生存预测时,看到屏幕上跳出"准确率82%"的提示,是否曾困惑:这个数字真的可靠吗?为什么同一个数据集上逻辑回归和梯度提升树的准确率相近,但实际预测效果却大相径庭?本文将带你穿透表象,掌握模型评估的核心方法论。
在Titanic数据集中,假设62%的乘客最终遇难。如果一个模型简单预测所有乘客都死亡,它的准确率就能达到62%——这显然不是我们想要的"智能"预测。这就是著名的准确率悖论。
让我们用以下代码生成一个基础的混淆矩阵:
python复制from sklearn.metrics import confusion_matrix
import seaborn as sns
# 假设y_true是真实标签,y_pred是模型预测
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(cm, annot=True, fmt='d')
在生存预测场景中,混淆矩阵的四个象限对应着:
基于混淆矩阵,我们可以计算更细致的评估指标:
| 指标 | 公式 | Titanic场景中的意义 |
|---|---|---|
| 精确率(Precision) | TP/(TP+FP) | 预测为幸存者中实际幸存的比例 |
| 召回率(Recall) | TP/(TP+FN) | 实际幸存者中被正确识别的比例 |
| F1分数 | 2*(Precision*Recall)/(Precision+Recall) | 精确率和召回率的调和平均 |
在Titanic案例中,我们可能更关注召回率——因为漏救一个幸存者(FN)的代价远高于误救一个遇难者(FP)。
机器学习模型通常先输出概率值(如0-1之间的生存概率),然后通过阈值(默认0.5)转换为分类结果。调整这个阈值会同时影响FP和TP的比例。
python复制from sklearn.metrics import roc_curve
# 获取模型预测概率
y_scores = model.predict_proba(X_test)[:, 1]
# 计算ROC曲线
fpr, tpr, thresholds = roc_curve(y_true, y_scores)
理想的ROC曲线会紧贴左上角,这意味着:
在Titanic数据上比较两种模型:
code复制Model AUC
GradientBoosting 0.87
LogisticRegression 0.83
虽然两者准确率相近,但AUC的差异揭示了梯度提升树具有更好的区分能力。
单次训练测试划分可能具有偶然性。以下是5折交叉验证示例:
python复制from sklearn.model_selection import cross_val_score
scores = cross_val_score(
estimator=model,
X=X_train,
y=y_train,
cv=5, # 5折
scoring='accuracy'
)
print(f"平均准确率: {scores.mean():.2f} (±{scores.std():.2f})")
用箱线图展示不同模型的交叉验证结果分布:
python复制import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))
plt.boxplot([gb_scores, lr_scores], labels=['GradientBoosting', 'LogisticRegression'])
plt.title('5-Fold CV Accuracy Comparison')
plt.ylabel('Accuracy')
这种可视化能清晰展示模型表现的稳定性和离群情况。
建立一个决策矩阵帮助选择:
| 评估维度 | GradientBoosting | LogisticRegression | 权重 |
|---|---|---|---|
| 准确率 | 0.82 | 0.81 | 30% |
| AUC | 0.87 | 0.83 | 25% |
| 训练速度 | 较慢 | 快 | 15% |
| 可解释性 | 中等 | 高 | 20% |
| 内存消耗 | 较高 | 低 | 10% |
根据实际需求调整评估重点:
在Titanic案例中,我们可能更倾向于选择召回率较高的模型,即使其整体准确率略低。
有些模型输出的概率并不反映真实可能性。校准曲线可以检验:
python复制from sklearn.calibration import calibration_curve
prob_true, prob_pred = calibration_curve(y_true, y_prob, n_bins=10)
plt.plot(prob_pred, prob_true, marker='o')
理想情况下曲线应接近对角线。
对于欠校准的模型,可以使用:
python复制from sklearn.calibration import CalibratedClassifierCV
calibrated = CalibratedClassifierCV(model, method='isotonic', cv=3)
calibrated.fit(X_train, y_train)
这在生存概率预测等需要精确概率值的场景特别有用。
类别不平衡处理:Titanic数据存在生存/遇难比例不平衡,可考虑:
特征重要性检验:避免被无意义特征干扰
python复制importances = model.feature_importances_
sorted_idx = importances.argsort()[::-1]
plt.barh(range(10), importances[sorted_idx][:10])
plt.yticks(range(10), X.columns[sorted_idx][:10])
在Titanic项目中,我曾发现将年龄预测模型应用于整个数据集(包含测试集)会导致评估指标虚高——这是典型的数据泄露案例。正确的做法是仅使用训练集数据训练年龄预测模型,然后应用于测试集。