理解为什么在训练数据上表现良好的模型可能在现实世界中失败。学会使用稳健的验证技术检测、预防和度量过拟合。
过拟合发生在模型过度学习训练数据时——包括噪声和随机模式——而不是一般模式。结果:
想象一个学生死记硬背考试答案而不是理解概念。在真正的考试中,他们失败了。
最简单的方法:比较在训练集与验证/测试集上的表现。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
模型 = LogisticRegression()
模型.fit(X_train, y_train)
# 训练表现
y_train_pred = 模型.predict(X_train)
train_acc = accuracy_score(y_train, y_train_pred)
# 测试表现
y_test_pred = 模型.predict(X_test)
test_acc = accuracy_score(y_test, y_test_pred)
print(f"训练准确性: {train_acc:.4f}")
print(f"测试准确性: {test_acc:.4f}")
# 如果 train_acc >> test_acc → 过拟合!
⚠️ 典型例子:
在损失函数中添加惩罚项以防止系数变得过大。
# 带L2正则化(Ridge)的逻辑回归
模型_l2 = LogisticRegression(penalty='l2', C=1.0) # 更小的C = 更多正则化
# 使用L1(Lasso)进行自动特征选择
模型_l1 = LogisticRegression(penalty='l1', solver='liblinear', C=0.1)
✅ L1(Lasso): 可以将系数置零 → 特征选择。
✅ L2(Ridge): 收缩系数但不置零 → 更稳定。
简单但强大。更多有代表性的数据帮助模型学习更一般的模式。
在看到测试数据之前评估模型泛化能力的最佳工具。
简单的验证(训练/测试分割)如果分割幸运或不幸可能会误导。
交叉验证(CV) 将数据分割为K折,训练K次,每次使用不同的折作为验证。
结果:更稳健、可靠的表现估计。
from sklearn.model_selection import cross_val_score
模型 = LogisticRegression()
# 5折交叉验证
scores = cross_val_score(模型, X_train, y_train, cv=5, scoring='roc_auc')
print(f"每折AUC-ROC: {scores}")
print(f"平均AUC-ROC: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
✅ 优点:
分割为K个相等部分。每折使用一次作为验证。
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
在每折中保持类别比例。对不平衡数据集特别重要。
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(模型, X_train, y_train, cv=skf, scoring='roc_auc')
每折是单个观测。计算成本非常高;仅适用于非常小的数据集。
import numpy as np
# 使用简单的训练/测试进行训练和评估
模型.fit(X_train, y_train)
test_score = roc_auc_score(y_test, 模型.predict_proba(X_test)[:,1])
# 在训练集上使用交叉验证进行评估
cv_scores = cross_val_score(模型, X_train, y_train, cv=5, scoring='roc_auc')
plt.figure(figsize=(8,5))
plt.axhline(y=test_score, color='red', linestyle='--', label=f'测试分数: {test_score:.4f}')
plt.plot(range(1,6), cv_scores, 'bo-', label='每折交叉验证分数')
plt.axhline(y=cv_scores.mean(), color='blue', linestyle='-', label=f'交叉验证平均: {cv_scores.mean():.4f}')
plt.title("比较:交叉验证 vs 最终测试")
plt.xlabel("折")
plt.ylabel("AUC-ROC")
plt.legend()
plt.grid()
plt.show()
数据集: 欺诈_特征.csv(预处理后的选定特征)
任务:
C=0.01)并比较。