class_weight不能直接用于交叉验证,因其基于每折训练集单独计算,易导致权重失衡;应手动用compute_sample_weight为每折生成sample_weight并传入fit()。

为什么 class_weight 不能直接用于交叉验证的训练集加权
很多人以为给 sklearn 模型传入 class_weight="balanced" 就能自动适配 CV 的每次折——其实不然。CV 过程中,train_test_split 或 StratifiedKFold 默认只保证类别比例在各折间一致,但模型训练时的 class_weight 是基于**当前 fold 的训练集**单独计算的。如果某折里少数类样本极少(比如只有1个),"balanced" 会把它权重拉得极高,导致训练不稳定甚至发散。
真正可控的方式是:手动为每折的训练集计算权重,并传给 fit() 的 sample_weight 参数。
用 compute_sample_weight 生成每折的 sample_weight
sklearn.utils.class_weight.compute_sample_weight 是唯一推荐的权重生成函数,它支持 "balanced" 和 "balanced_subsample" 两种策略,且可指定 y(当前 fold 的训练标签)来精确计算。
- 用
"balanced":权重 =n_samples / (n_classes * n_samples_in_class),适合全局不平衡场景 - 用
"balanced_subsample":只按当前折的训练集统计频次,更适合 CV 中各折分布不均的情况 - 务必在每次
fit()前调用,不能复用上一折的权重数组
示例:
from sklearn.utils.class_weight import compute_sample_weight
from sklearn.model_selection import StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
<p>X, y = load_data() # 假设 y 有严重倾斜
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
model = RandomForestClassifier()</p><p>for train_idx, val_idx in cv.split(X, y):
X_train, y_train = X[train_idx], y[train_idx]
X_val, y_val = X[val_idx], y[val_idx]</p><pre class="brush:php;toolbar:false;"># 关键:只为当前 fold 的 y_train 计算权重
sample_weight = compute_sample_weight("balanced_subsample", y=y_train)
model.fit(X_train, y_train, sample_weight=sample_weight)
score = model.score(X_val, y_val)
评估指标必须匹配业务目标,不能只看 accuracy
带权重的 CV 不等于问题解决——如果评估仍用 accuracy,少数类提升会被多数类淹没。CV 循环中必须记录能反映倾斜敏感度的指标:
-
f1_score(y_val, y_pred, average="weighted")或average="macro",避免被多数类主导 -
classification_report(y_val, y_pred)看各类别的 precision/recall/f1 - 对二分类,优先用
roc_auc_score(y_val, y_proba[:, 1]),它不依赖阈值
注意:cross_val_score 默认不支持传 sample_weight,所以必须手写 CV 循环,否则权重根本没生效。
验证集是否也要加权?一般不用
验证集(val set)加权没有理论依据:它的作用是模拟真实预测场景,而真实场景中你无法提前知道每个样本该有多“重要”。加权验证集只会让指标失真,比如人为抬高少数类预测得分,掩盖模型在多数类上的过拟合。
唯一例外是:你的业务明确要求「错判少数类的代价是错判多数类的 N 倍」,且这个代价已量化为损失函数——此时应改用自定义损失(如 class_weight 配合 LogisticRegression 的 loss="log_loss"),而不是在验证时加权。
记住:权重只用于训练信号校正,验证必须保持“原生分布”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











