分类样本不平衡怎么处理?比较 class_weight 前后的少数类召回

固定同一测试集对比多数类、普通逻辑回归和 balanced 权重,查看少数类召回改善伴随的误报代价。

少数类只有几个百分点时,一个永远预测多数类的模型也可能有很高准确率。class_weight=”balanced” 会在训练损失中改变不同类别的权重,可以帮助模型重视少数类,但常伴随误报增加。应固定数据划分,同时比较少数类召回、精确率和混淆矩阵。

先看多数类基线会漏掉什么

示例核对环境为 Python 3.11、scikit-learn 1.9.1、NumPy 2.4.6;涉及表格的代码还使用 pandas 3.0.6。资料核对日期为 2026 年 10 月 1 日。代码在 CPU 上运行,不需要账号、API 密钥或下载预训练权重。

分类样本不平衡怎么处理?比较 class_weight 前后的少数类召回

下方生成 1,500 条人为构造的二分类数据,标签 1 作为演示的少数类。weights 设置的是生成分布目标,加上标签噪声后实际比例不会严格等于 6%;应使用打印出的计数。这里没有欺诈、疾病或风险等级的真实案例,不能据此承诺提升某个业务效果。

召回率表示真正的少数类有多少被找到,精确率表示被报成少数类的样本有多少正确。官方评估指南可核对这两个指标和混淆矩阵。例中的 zero_division=0 只是让没有正类预测时指标有明确定义,不代表失败已经消失。

固定测试集,对照三种训练设置

python -m venv .venv
# Windows PowerShell 中使用这个环境的解释器:
.\.venv\Scripts\python.exe -m pip install scikit-learn==1.9.1 numpy==2.4.6 pandas==3.0.6
.\.venv\Scripts\python.exe demo.py

把下方完整 Python 代码保存为 demo.py,再运行最后一条命令。macOS/Linux 使用 .venv/bin/python 代替 Windows 路径。安装需要网络;完成安装后,这些示例的数据在代码中生成,可离线运行。使用其他版本时先打印 sklearn.__version__,不要把两个环境的报错混在一起排查。

先运行下方脚本,三种模型使用完全相同的训练和测试记录。带权与不带权的逻辑回归只有 class_weight 的主要差别。LogisticRegression 官方文档说明 balanced 根据训练类别频率自动计算权重,比例由训练数据决定,不读取测试集的真实标签。

from collections import Counter
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix

X, y = make_classification(n_samples=1500, n_features=8, n_informative=4,
                          n_redundant=0, weights=[0.94, 0.06],
                          class_sep=0.8, flip_y=0.01, random_state=19)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, stratify=y, random_state=19)
print("test counts", dict(Counter(y_test)))
models = [("majority", DummyClassifier(strategy="most_frequent")),
          ("unweighted", make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))),
          ("balanced", make_pipeline(StandardScaler(), LogisticRegression(
              max_iter=1000, class_weight="balanced")))]
for name, model in models:
    model.fit(X_train, y_train)
    pred = model.predict(X_test)
    print(name, "acc/precision/recall", [round(x, 3) for x in (
        accuracy_score(y_test, pred), precision_score(y_test, pred, zero_division=0),
        recall_score(y_test, pred, zero_division=0))])
    print("confusion", confusion_matrix(y_test, pred, labels=[0, 1]).tolist())

把召回改善和误报代价放在一起看

test counts {np.int64(0): 421, np.int64(1): 29}
majority acc/precision/recall [0.936, 0.0, 0.0]
confusion [[421, 0], [29, 0]]
unweighted acc/precision/recall [0.947, 0.857, 0.207]
confusion [[420, 1], [23, 6]]
balanced acc/precision/recall [0.829, 0.2, 0.552]
confusion [[357, 64], [13, 16]]

测试集有 421 条标签 0 和 29 条标签 1。多数类基线准确率约 0.936,但漏掉了全部 29 条少数类。无权重模型找到 6 条、漏掉 23 条;balanced 模型找到 16 条、漏掉 13 条,同时把标签 0 的误报从 1 条增加到 64 条。这就是不能把“少数类召回上升”单独当作成功的原因。

验证方法是固定 labels=[0, 1] 手算第二行的 TP/(TP+FN),并检查第一行的误报数量。若你的标签名称和顺序不同,先调整正类定义。正式选择需要给出漏报与误报的处理成本,例如复核人力是否能承受更多候选;不能从这个演示替业务决定阈值或上线标准。

替换真实数据时保留可解释的对照

先核对少数类标签质量、各来源分布和独立验证方式。如果少数类本身被错标或只来自单一设备,加权并不能修复这些问题。不要同时重采样、改阈值、换模型再把全部变化归功于 balanced。

class_weight 改的是训练损失权重,并不复制少数类样本,也不保证预测概率保持原始发生率意义。若后续用概率做业务决策,应另外检查概率质量。类别极少时一次随机测试的召回会波动,需按真实样本关系设计重复验证,并保留失败样本。

本例给出的结论是:权重能改变错误分布,是否值得采用取决于你能接受的错误方向和代价。运行成功、总准确率高或某个指标变好,都不足以独立决定正式发布模型。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30572.html

赞 (0)
AI小管家的头像AI小管家
模型输出的概率可信吗?用 CalibratedClassifierCV 校准并核对 Brier 分数
上一篇 1天前
回归模型误差怎么看?用 MAE、RMSE 和残差表定位大误差
下一篇 1天前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部