You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理分类问题中的不平衡数据?附Python实现与评估指南

不平衡二分类任务的解决方案与实践

必须关注的性能指标

不平衡数据下,准确率完全没用——模型只要全预测多数类(Class A)就能拿到80%的准确率,根本无法体现对少数类的识别能力。你需要重点关注这些指标:

  • 混淆矩阵:直观查看少数类(Class B)的正确预测数(TP)、漏判数(FN),以及多数类的误判数(FP)
  • 召回率(Recall/TPR):真正的Class B样本中被正确识别的比例,公式为 TP/(TP+FN)——这是衡量模型是否能有效捕捉少数类的核心指标
  • 精确率(Precision):预测为Class B的样本中真正属于B的比例,公式为 TP/(TP+FP)——避免模型把太多A误判成B
  • F1分数:精确率和召回率的调和平均,公式为 2*(Precision*Recall)/(Precision+Recall)——平衡两者的综合表现
  • PR-AUC(精确率-召回率曲线下面积):比ROC-AUC更适合不平衡场景,ROC-AUC对少数类的性能变化不敏感,而PR-AUC能直接反映模型在少数类上的表现

不平衡数据处理方案(Scikit-learn + imblearn实现)

以下是针对你的场景的具体代码,假设X是特征矩阵,y是标签(0=Class A,1=Class B):

1. 类别权重调整(最简单高效的首选方案)

大部分Scikit-learn分类器支持class_weight参数,自动给少数类分配更高权重,无需修改原始数据。

from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix

# 分层划分训练集/测试集,保证类别比例与原始数据一致
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# Logistic Regression 带类别权重
lr = LogisticRegression(
    class_weight='balanced', random_state=42, max_iter=1000
)
lr.fit(X_train, y_train)
y_pred_lr = lr.predict(X_test)
print("Logistic Regression(带类别权重)结果:")
print(confusion_matrix(y_test, y_pred_lr))
print(classification_report(y_test, y_pred_lr))

# Random Forest 带类别权重
rf = RandomForestClassifier(
    class_weight='balanced', random_state=42, n_estimators=100
)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
print("\nRandom Forest(带类别权重)结果:")
print(confusion_matrix(y_test, y_pred_rf))
print(classification_report(y_test, y_pred_rf))

说明:class_weight='balanced'会根据样本比例自动计算权重,公式为 n_samples / (n_classes * np.bincount(y)),少数类的权重会更高。

2. 过采样(增加少数类样本)

如果类别权重效果不佳,可尝试过采样。SMOTE是生成合成少数类样本的方法,比直接复制少数类(随机过采样)更能避免过拟合。

from imblearn.over_sampling import SMOTE, RandomOverSampler

# SMOTE 合成少数类样本
smote = SMOTE(random_state=42)
X_resampled_smote, y_resampled_smote = smote.fit_resample(X_train, y_train)
# 训练Random Forest
rf_smote = RandomForestClassifier(random_state=42)
rf_smote.fit(X_resampled_smote, y_resampled_smote)
y_pred_smote = rf_smote.predict(X_test)
print("SMOTE过采样后模型结果:")
print(classification_report(y_test, y_pred_smote))

# 随机过采样(仅做对比,不推荐优先使用)
ros = RandomOverSampler(random_state=42)
X_resampled_ros, y_resampled_ros = ros.fit_resample(X_train, y_train)
rf_ros = RandomForestClassifier(random_state=42)
rf_ros.fit(X_resampled_ros, y_resampled_ros)
y_pred_ros = rf_ros.predict(X_test)
print("\n随机过采样后模型结果:")
print(classification_report(y_test, y_pred_ros))

3. 欠采样(减少多数类样本)

仅在数据量极大(比如百万级样本)时考虑,因为会丢失多数类的关键信息。NearMiss是智能欠采样方法,保留与少数类更相似的多数类样本。

from imblearn.under_sampling import NearMiss, RandomUnderSampler

# NearMiss 智能欠采样
nm = NearMiss(version=1)
X_resampled_nm, y_resampled_nm = nm.fit_resample(X_train, y_train)
rf_nm = RandomForestClassifier(random_state=42)
rf_nm.fit(X_resampled_nm, y_resampled_nm)
y_pred_nm = rf_nm.predict(X_test)
print("NearMiss欠采样后模型结果:")
print(classification_report(y_test, y_pred_nm))

# 随机欠采样(仅做对比)
rus = RandomUnderSampler(random_state=42)
X_resampled_rus, y_resampled_rus = rus.fit_resample(X_train, y_train)
rf_rus = RandomForestClassifier(random_state=42)
rf_rus.fit(X_resampled_rus, y_resampled_rus)
y_pred_rus = rf_rus.predict(X_test)
print("\n随机欠采样后模型结果:")
print(classification_report(y_test, y_pred_rus))

4. 集成方法(采样+模型的最优组合)

集成方法通常比单一采样+模型的效果更好,推荐使用BalancedRandomForest或EasyEnsemble:

from imblearn.ensemble import BalancedRandomForestClassifier, EasyEnsembleClassifier

# Balanced Random Forest:每个树训练时对多数类欠采样
brf = BalancedRandomForestClassifier(random_state=42, n_estimators=100)
brf.fit(X_train, y_train)
y_pred_brf = brf.predict(X_test)
print("Balanced Random Forest结果:")
print(classification_report(y_test, y_pred_brf))

# Easy Ensemble:对多数类多次欠采样,训练多个模型集成
ee = EasyEnsembleClassifier(random_state=42, n_estimators=100)
ee.fit(X_train, y_train)
y_pred_ee = ee.predict(X_test)
print("\nEasy Ensemble结果:")
print(classification_report(y_test, y_pred_ee))

最佳实践总结

  1. 优先尝试类别权重调整:实现简单,不修改原始数据,适合大多数场景,尤其是数据量中等的情况。
  2. 其次选择SMOTE过采样:比随机过采样更稳健,减少过拟合风险,适合特征空间连续的数据集。
  3. 欠采样仅在数据量极大时使用:避免丢失多数类的重要信息,优先用NearMiss而非随机欠采样。
  4. 集成方法是复杂数据集的最优选择:Balanced RF和Easy Ensemble能兼顾多数类和少数类的性能。
  5. 始终分层划分数据集:用stratify=y保证训练集和测试集的类别比例与原始数据一致,避免评估偏差。
  6. 坚决抛弃准确率:重点关注少数类的召回率、F1分数、PR-AUC,这些指标才能真实反映模型性能。

内容的提问来源于stack exchange,提问作者Viper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:20:17