cross_val_score默认不进行分层抽样,需显式传入StratifiedKFold实例;shuffle=True和random_state固定是关键;scoring应依业务目标选recall/f1/precision等;需手动循环获取每折详细报告以诊断问题。

cross_val_score 默认不保证分层抽样,必须显式指定 cv 参数为分层 K 折
很多人误以为 cross_val_score 会自动按类别比例切分训练/验证集,其实不会。默认的 cv=5 是普通 KFold,遇到类别极度不平衡(比如正样本仅占 2%)时,某些折可能完全没正样本,导致 F1 或 precision 算出来是 0 或 nan,评估结果失真。
正确做法是用 StratifiedKFold 并传给 cv 参数:
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(
estimator=RandomForestClassifier(),
X=X, y=y,
cv=skf,
scoring='f1'
)
-
shuffle=True很关键:否则数据若按类别排好序(如前 100 行全是 0,后 5 行全是 1),StratifiedKFold仍会按原始顺序切分,分层失效 -
random_state要固定,否则每次运行cross_val_score结果不同,无法复现 - 别用
cv=5加stratify=y这种写法——cross_val_score不接受stratify参数
scoring 选错会导致泛化能力被高估,尤其在不平衡数据上
用 scoring='accuracy' 在类别不平衡时几乎没意义。比如负样本占 98%,模型全预测为负,准确率也有 98%,但完全没判出正样本。
真正反映泛化能力的指标得看业务目标:
- 关注“找全正样本” → 用
'recall'或'f1' - 关注“预测出来的正样本是否靠谱” → 用
'precision' - 兼顾两者且类别极不平衡 → 用
'f1_weighted'或'average_precision'(后者对阈值更鲁棒) - 需要概率输出校准 → 配合
'roc_auc',但要求模型支持predict_proba
注意:'f1' 默认是二分类的 macro 平均,等价于 f1_score(y_true, y_pred, average='binary');如果传了 y 是多类,它会自动切到 macro 模式,行为易混淆。
cross_val_score 返回的是单个数组,不是每折的详细报告
它只返回每个 fold 的标量分数(如 5 个 f1 值),没法看到每折的 confusion_matrix、classification_report 或预测概率分布。一旦某折分数异常低,你不知道是过拟合、数据泄露还是标签噪声。
要深挖问题,得手动展开交叉验证循环:
f1
分数是 [0.62, 0.65, 0.63, 0.41, 0.64],平均 0.63 看着还行,但第四折只有 0.41——说明模型对某个子分布极其敏感,泛化能力实际很弱。
建议始终检查:
- 分数标准差:>0.05 就值得警惕
- 最小值是否低于平均值 2 个标准差
- 是否某折的
support(样本数)明显偏少(StratifiedKFold通常能避免,但极小数据集下仍可能)
交叉验证只是近似估计,真实泛化能力最终取决于测试集分布是否与训练/验证过程一致。这点容易被忽略,尤其当线上数据分布悄悄漂移时。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











