类别不平衡处理:过采样、欠采样、SMOTE

一句话概述

类别不平衡(Class Imbalance)是指分类任务中各类别样本数量差距悬殊的情况——如欺诈检测中 99.9% 是正常交易、0.1% 是欺诈。在不平衡数据上训练的标准分类器会倾向于预测多数类,导致少数类的召回率极低。处理方法分为数据层面和算法层面:数据层面包括欠采样(减少多数类)、过采样(复制少数类)和 SMOTE(合成少数类样本);算法层面包括代价敏感学习、阈值调整和集成方法。

💡 核心要点:① 类别不平衡的核心问题是模型被多数类「淹没」,忽略了少数类的模式 ② 欠采样简单但丢弃信息,过采样简单但易过拟合,SMOTE 是合成样本的折中方案 ③ 在不平衡场景中,准确率是误导性指标——应该关注精确率、召回率、F1 和 AUC ④ 工业级方案通常组合数据级和算法级方法,如 SMOTE + 代价敏感学习

教学与演示

一、类别不平衡的问题与评估

是什么:类别不平衡是指分类问题中各类别样本数量差异显著的情况。多数类(Majority Class)样本远多于少数类(Minority Class)。在极端情况下(如欺诈检测 1:10000),标准分类器可能简单地预测所有样本为多数类,获得 99.99% 的准确率,但对少数类毫无预测能力——而这种「高准确率」完全是误导性的。

大白话 就像一个班级有 99 个男生和 1 个女生,如果模型「偷懒」地把所有人都预测为男生,准确率就有 99%——但这显然不是我们想要的。类别不平衡就是让模型「偷懒」太容易了。

为什么:类别不平衡影响模型的根本原因是:大多数分类器的训练目标是最小化整体错误率(或交叉熵),这意味着模型对多数类的关注远大于少数类。从梯度角度看,多数类样本贡献的梯度总和远大于少数类,模型被「拖着走」。此外,少数类样本的决策边界可能非常模糊(样本太少,边界难以确定),进一步加剧了问题。

怎么做

import numpy as np

# ========== 类别不平衡的影响演示 ==========
np.random.seed(42)

def class_imbalance_demo():
    """演示类别不平衡对分类器的影响"""
    n_majority = 990  # 多数类数量
    n_minority = 10   # 少数类数量
    
    # 生成不平衡数据
    # 多数类(类别0):中心在 (0, 0)
    X_maj = np.random.randn(n_majority, 2) * 1.5
    y_maj = np.zeros(n_majority)
    
    # 少数类(类别1):中心在 (3, 3)
    X_min = np.random.randn(n_minority, 2) * 0.5 + np.array([3, 3])
    y_min = np.ones(n_minority)
    
    X = np.vstack([X_maj, X_min])
    y = np.hstack([y_maj, y_min])
    
    # 打乱数据
    idx = np.random.permutation(len(X))
    X, y = X[idx], y[idx]
    
    imbalance_ratio = n_majority / n_minority
    print("=== 类别不平衡问题 ===")
    print(f"多数类(类别0): {n_majority} 个样本")
    print(f"少数类(类别1): {n_minority} 个样本")
    print(f"不平衡比例: {imbalance_ratio:.0f}:1")
    print()
    
    # 模拟「偷懒分类器」——全部预测为多数类
    lazy_pred = np.zeros(len(y))
    print("--- 「偷懒分类器」的性能 ---")
    print(f"预测全部为 0(多数类)")
    accuracy = np.mean(lazy_pred == y)
    
    # 各类别的准确率
    maj_mask = y == 0
    min_mask = y == 1
    maj_acc = np.mean(lazy_pred[maj_mask] == y[maj_mask])
    min_acc = np.mean(lazy_pred[min_mask] == y[min_mask])
    
    print(f"整体准确率: {accuracy:.2%}")
    print(f"多数类准确率: {maj_acc:.2%}")
    print(f"少数类准确率: {min_acc:.2%} ← 完全失败!")
    print()
    
    print("重要教训:高准确率 ≠ 好模型(在不平衡数据中)")
    print("应该使用:精确率(Precision)、召回率(Recall)、F1、AUC")
    print()
    
    # 计算正确的评估指标
    # 模拟一个还不错的分类器预测
    good_pred = np.zeros(len(y))
    # 正确预测少数类(但有一些错误)
    good_pred[min_mask] = np.random.choice([0, 1], n_minority, p=[0.3, 0.7])
    # 正确预测多数类(但有少量错误)
    good_pred[maj_mask] = np.random.choice([0, 1], n_majority, p=[0.95, 0.05])
    
    tp = np.sum((good_pred == 1) & (y == 1))  # True Positive
    fp = np.sum((good_pred == 1) & (y == 0))  # False Positive
    fn = np.sum((good_pred == 0) & (y == 1))  # False Negative
    
    precision = tp / (tp + fp) if (tp + fp) > 0 else 0
    recall = tp / (tp + fn) if (tp + fn) > 0 else 0
    f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
    
    print(f"--- 使用正确的评估指标 ---")
    print(f"精确率 (Precision): {precision:.3f} (预测为少数类的样本中真正是少数类的比例)")
    print(f"召回率 (Recall): {recall:.3f} (真正的少数类中被正确识别的比例)")
    print(f"F1 分数: {f1:.3f} (精确率和召回率的调和平均)")

class_imbalance_demo()
\text{不平衡场景中的正确评估指标}\(\text{Precision} = \frac{TP}{TP + FP}, \quad \text{Recall} = \frac{TP}{TP + FN}, \quad F_1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}}\)
大白话 在不平衡数据中,准确率就像「只看总分不看单科成绩」——总分很高但挂了一科。精确率、召回率和 F1 才是真正能反映你「弱项」考得怎么样的指标。

二、欠采样(Undersampling)

是什么:欠采样通过减少多数类样本数量来平衡类别比例。最简单的方法是随机欠采样——从多数类中随机抽取与少数类相同数量的样本。更高级的方法包括 Tomek Links(删除边界附近的多类样本)、Edited Nearest Neighbors(删除被近邻误分类的样本)和 NearMiss(选择与少数类最近的多数类样本)。

大白话 欠采样就是「把多的砍掉一些」——如果男生太多、女生太少,就随机去掉一些男生,让男女比例平衡。问题是你去掉的男生可能包含重要信息。

为什么:欠采样简单有效,但最大问题是信息丢失——丢弃的多数类样本可能包含有价值的模式。当多数类样本之间存在子类结构时,随机欠采样可能破坏这些子类。Tomek Links 和 NearMiss 等方法试图「有选择地」删除样本——删除的是边界模糊的或有噪声的样本——而不是随机删除,从而减少信息损失。

怎么做

import numpy as np

# ========== 欠采样方法演示 ==========
np.random.seed(42)

def undersampling_demo():
    """演示各种欠采样方法"""
    # 生成不平衡数据
    n_maj, n_min = 500, 50
    
    # 多数类:两个子簇
    X_maj1 = np.random.randn(n_maj // 2, 2) * 1.5 + np.array([-3, 0])
    X_maj2 = np.random.randn(n_maj // 2, 2) * 1.5 + np.array([3, 0])
    X_maj = np.vstack([X_maj1, X_maj2])
    y_maj = np.zeros(n_maj)
    
    # 少数类:中心在原点
    X_min = np.random.randn(n_min, 2) * 0.8
    y_min = np.ones(n_min)
    
    print("=== 欠采样方法 ===")
    print(f"原始数据: 多数类={n_maj}, 少数类={n_min}")
    print(f"不平衡比例: {n_maj/n_min:.0f}:1")
    print()
    
    # 方法1:随机欠采样
    print("--- 方法1:随机欠采样 ---")
    undersample_size = n_min  # 采样到与少数类相同
    undersample_idx = np.random.choice(n_maj, undersample_size, replace=False)
    X_maj_under = X_maj[undersample_idx]
    print(f"  多数类从 {n_maj} → {len(X_maj_under)} 个样本")
    print(f"  新的类别比例: {undersample_size}:{n_min} = 1:1")
    print(f"  优点: 简单快速")
    print(f"  缺点: 丢弃了 {n_maj - undersample_size} 个多数类样本的信息")
    
    # 方法2:Tomek Links(概念演示)
    print("\n--- 方法2:Tomek Links(概念)---")
    print("  Tomek Link: 两个不同类别样本互为最近邻")
    print("  删除 Tomek Link 中的多数类样本 → 清理决策边界")
    print("  优点: 比随机欠采样更智能(只删除边界模糊的样本)")
    print("  缺点: 删除的样本数不可控,可能删得不够")
    
    # 方法3:NearMiss(概念演示)
    print("\n--- 方法3:NearMiss(概念)---")
    print("  NearMiss-1: 选择与最近的少数类样本平均距离最小的多数类样本")
    print("  NearMiss-2: 选择与最远的少数类样本平均距离最小的多数类样本")
    print("  优点: 保留对分类最有用的多数类样本(靠近决策边界的)")
    print("  缺点: 计算最近邻需要 O(n²) 时间")
    
    print("\n欠采样的核心风险:信息丢失")
    print("  - 如果多数类有两个子簇(如本例),随机欠采样可能仅保留一个")
    print("  - 解决方案:使用聚类欠采样——先聚类,再从每个簇中等比例采样")

undersampling_demo()
大白话 欠采样的问题在于「扔掉的可能是宝贝」。如果多数类内部有很多「门派」(子类),随机削减可能导致某些门派全军覆没。Tomek Links 和 NearMiss 帮你「精挑细选」——只扔边界模糊的,保留有代表性的。

三、过采样与 SMOTE

是什么:过采样通过增加少数类样本来平衡类别比例。最简单的方法是随机过采样——直接复制少数类样本。SMOTE(Synthetic Minority Over-sampling Technique,Chawla et al., 2002)是更高级的方法——它不复制样本,而是在少数类样本之间进行线性插值,生成新的「合成」样本。SMOTE 有多种变体:Borderline-SMOTE(只在边界生成)、ADASYN(自适应生成)、SMOTE-ENN(生成后清洗)。

大白话 过采样就是「给少数派补充兵力」——最笨的方法是复制粘贴(随机过采样),聪明的方法是「人造新兵」(SMOTE):在两个少数类样本之间取中点或任意点,创造出新的合理的少数类样本。

为什么:随机过采样简单但会导致严重的过拟合——复制样本等于让模型在这些样本上重复学习,决策边界会过度收紧。SMOTE 通过合成新样本来扩张少数类的「领地」,帮助模型学习更广泛的少数类模式。SMOTE 的核心思想是:在特征空间中,少数类样本之间的连线上的点很可能也是少数类。

怎么做

import numpy as np

# ========== SMOTE 算法实现演示 ==========
np.random.seed(42)

def smote_demo():
    """从零实现 SMOTE 算法"""
    print("=== SMOTE(合成少数类过采样)===")
    
    # 原始少数类样本(5个点)
    X_min = np.array([
        [1.0, 2.0],
        [1.5, 2.5],
        [2.0, 2.0],
        [2.5, 3.0],
        [1.5, 1.5],
    ])
    
    print(f"原始少数类样本: {len(X_min)} 个")
    print("原始样本:")
    for i, x in enumerate(X_min):
        print(f"  样本{i}: ({x[0]:.1f}, {x[1]:.1f})")
    print()
    
    # SMOTE 参数
    k_neighbors = 3  # 最近邻数量
    sampling_ratio = 2  # 每个样本生成 2 个新样本
    
    def smote_single(X, k=3, ratio=2):
        """
        SMOTE 算法:对每个少数类样本,找到其 k 个最近邻,
        在样本与最近邻的连线上随机生成 ratio 个新样本
        """
        n_samples, n_features = X.shape
        synthetic_samples = []
        
        for i in range(n_samples):
            # 找到样本 i 的 k 个最近邻
            distances = np.sqrt(np.sum((X - X[i]) ** 2, axis=1))
            # 排除自身
            distances[i] = np.inf
            knn_indices = np.argsort(distances)[:k]
            
            # 为样本 i 生成 ratio 个合成样本
            for _ in range(ratio):
                # 随机选择一个最近邻
                nn_idx = np.random.choice(knn_indices)
                # 在样本 i 和最近邻之间随机插值
                alpha = np.random.random()  # 0~1 之间的随机数
                synthetic = X[i] + alpha * (X[nn_idx] - X[i])
                synthetic_samples.append(synthetic)
        
        return np.array(synthetic_samples)
    
    X_synthetic = smote_single(X_min, k=k_neighbors, ratio=sampling_ratio)
    
    print(f"SMOTE 生成的新样本: {len(X_synthetic)} 个 (每样本 ×{sampling_ratio})")
    print("合成样本:")
    for i, x in enumerate(X_synthetic):
        print(f"  合成{i}: ({x[0]:.2f}, {x[1]:.2f})")
    
    print(f"\nSMOTE 的核心公式: x_new = x_i + α · (x_nn - x_i)")
    print(f"  其中 α ∈ [0, 1] 是随机插值系数")
    print(f"  x_i 是原始少数类样本,x_nn 是其随机选中的一个最近邻")
    print(f"\nSMOTE 特点:")
    print(f"  优点: 不简单复制,生成多样化的新样本")
    print(f"  缺点: 如果少数类样本之间有多数类样本,SMOTE 会在多数类区域生成样本")
    print(f"         → 引入噪声 → Borderline-SMOTE 等变体解决此问题")

smote_demo()
\text{SMOTE 的合成样本公式}\(x_{\text{new}} = x_i + \alpha \cdot (x_{\text{nn}} - x_i), \quad \alpha \sim \text{Uniform}(0, 1)\)
大白话 SMOTE 就像一个「扩写作者」——它不是在抄原文(复制粘贴),而是根据已有内容创作新的合理内容。它在两个少数类样本之间画一条线,在线上随机取一个点作为新样本——这样新样本既有老样本的「基因」,又有一定的「变异」。

什么用:类别不平衡处理在 AI 工业中有海量应用场景:金融欺诈检测(正常交易 vs 欺诈交易,比例可高达 10000:1)、医疗诊断(健康 vs 患病)、工业缺陷检测(正常品 vs 缺陷品)、推荐系统中的负采样(点击 vs 曝光未点击)等。SMOTE 是最常用的数据级方法,而 XGBoost 的 scale_pos_weight 参数是最简单的算法级方法。

哪些坑:SMOTE 生成样本的质量取决于少数类样本的质量——如果少数类中有噪声样本,SMOTE 会扩散噪声。在高维空间中,SMOTE 的欧氏距离最近邻可能失去意义(维度灾难),建议先降维再做 SMOTE。SMOTE 默认用于数值特征,对于类别特征需要特殊处理(如 SMOTE-NC)。在极度不平衡(如 1:10000)时,单纯的数据级方法可能不足以解决问题。

四、综合策略与工业实践

是什么:在实际项目中,很少单独使用一种方法。常用的组合策略包括:① SMOTE + Tomek Links(SMOTETomek)——先生成少数类样本,再清理边界,② SMOTE + ENN(SMOTEENN)——生成后删除被误分类的样本,③ 数据级方法 + 算法级方法——SMOTE 过采样 + 代价敏感学习(如 class_weight),④ 集成方法——EasyEnsemble(多次欠采样 + 集成)和 BalanceCascade(级联欠采样)。

大白话 实战中不要只用一招——组合拳更强。生成新样本(SMOTE)扩大少数类的「地盘」,再清理战场(Tomek Links)扫除边界模糊的样本,最后用「更关注少数类」的模型(代价敏感学习)收尾。三重保险。

为什么:组合策略的优势在于各方法互补——SMOTE 解决了少数类样本不足的问题,Tomek Links 解决了 SMOTE 可能引入边界噪声的问题,代价敏感学习解决了模型优化目标偏向多数类的问题。EasyEnsemble 通过多次欠采样 + AdaBoost 集成,在几乎不损失多数类信息的前提下实现了类别平衡。

怎么做

import numpy as np

# ========== 综合策略总结 ==========
def comprehensive_strategy():
    """总结类别不平衡处理的综合策略"""
    print("=== 类别不平衡处理综合策略 ===")
    print()
    
    strategies = [
        ("数据层面", [
            ("随机欠采样", "简单,但丢失多数类信息", "多数类样本充足时"),
            ("随机过采样", "简单,但容易过拟合", "少数类样本极少时"),
            ("SMOTE", "合成新样本,信息更丰富", "数值特征为主"),
            ("SMOTE + Tomek", "生成+清理边界", "标准推荐"),
            ("EasyEnsemble", "多次欠采样+集成", "极度不平衡"),
        ]),
        ("算法层面", [
            ("class_weight='balanced'", "自动调整类别权重", "sklearn 模型"),
            ("代价敏感学习", "不同类别不同误分类代价", "业务有明确代价矩阵时"),
            ("阈值调整", "降低正类预测阈值", "需要提高召回率时"),
            ("Focal Loss", "降低易分类样本的权重", "深度学习场景"),
        ]),
        ("评估层面", [
            ("不使用 Accuracy", "改用 Precision/Recall/F1/AUC", "所有不平衡场景"),
            ("分层K折交叉验证", "保持每折类别比例", "标准评估流程"),
            ("PR 曲线 > ROC 曲线", "PR曲线对不平衡更敏感", "极度不平衡时"),
        ]),
    ]
    
    for category, items in strategies:
        print(f"【{category}】")
        for name, desc, scenario in items:
            print(f"  • {name:<20} {desc:<30} 适用: {scenario}")
        print()
    
    print("工业界最佳实践流程:")
    print("  1. 先从不平衡比例判断严重程度")
    print("  2. 1:10 ~ 1:100 → class_weight='balanced' 通常就够")
    print("  3. 1:100 ~ 1:1000 → SMOTE + class_weight")
    print("  4. 1:1000+ → SMOTE + EasyEnsemble / 专门的异常检测算法")
    print("  5. 始终用 F1/AUC/PR-AUC 评估,放弃 Accuracy")

comprehensive_strategy()
大白话 处理类别不平衡就像「打仗」——不能只用一种武器。先用 SMOTE「招兵买马」,再用 Tomek Links「清理边界」,最后给少数类「加薪」(class_weight)让模型更重视它们。不管用什么方法,记得用 F1 和 AUC 而不是准确率来评估战果。

概念关系图谱

方法类型操作对象主要风险适用不平衡比例
随机欠采样数据多数类信息丢失< 1:10
随机过采样数据少数类过拟合< 1:50
SMOTE数据少数类噪声扩散1:10 ~ 1:100
SMOTETomek数据(组合)两方实现复杂1:50 ~ 1:500
Class Weight算法损失函数需调权重1:2 ~ 1:100
EasyEnsemble集成多数类训练慢1:100+

重点答疑

Q1: 类别不平衡时,为什么准确率是一个坏指标?

因为准确率 = (TP+TN)/(TP+TN+FP+FN)。当多数类占 99% 时,模型只要预测全部为多数类就能获得 99% 的准确率,但对少数类的召回率为 0%。这种「高分低能」的现象在不平衡场景中非常普遍。应该使用精确率、召回率、F1、AUC-ROC 和 PR-AUC 等不受类别分布影响的指标。

Q2: SMOTE 和随机过采样有什么区别?SMOTE 更好吗?

随机过采样是直接复制少数类样本,SMOTE 是合成新的少数类样本。SMOTE 通常更好,因为:① 不会导致模型在重复样本上过度学习(降低过拟合),② 生成的样本具有多样性(插值系数 α 随机),③ 扩张了少数类的决策区域。但 SMOTE 也有缺点:如果少数类样本中有噪声,SMOTE 会扩散噪声;在高维空间中效果可能不好。

Q3: 极度不平衡(如 1:10000)应该怎么处理?

极度不平衡需要组合策略:① 先用专门的异常检测算法(如 Isolation Forest、One-Class SVM)而非传统分类器,② 如果必须用分类器,使用 EasyEnsemble(多次欠采样 + AdaBoost 集成),③ 在算法层面使用 Focal Loss 或代价敏感学习,④ 考虑将问题转化为排序问题(Learning to Rank),⑤ 评估时使用 PR-AUC 而非 ROC-AUC。

章节单词汇总

英文音标术语/释义
Class Imbalance/klæs ɪmˈbæləns/类别不平衡;各类别样本数量差距悬殊
Undersampling/ˈʌndərˌsæmplɪŋ/欠采样;减少多数类样本
Oversampling/ˈoʊvərˌsæmplɪŋ/过采样;增加少数类样本
SMOTE/smoʊt/Synthetic Minority Over-sampling;合成少数类过采样
Tomek Links/ˈtoʊmek lɪŋks/Tomek 对;互为最近邻的不同类样本对
Precision/prɪˈsɪʒən/精确率;预测为正的样本中真正的比例
Recall/rɪˈkɔːl/召回率;真正的正样本中被找到的比例
F1 Score/ef wʌn skɔːr/F1 分数;精确率和召回率的调和平均

面试练习

Q1 [单选] 在类别不平衡数据中,以下哪个指标最能反映模型对少数类的预测能力?

  • A. 准确率(Accuracy)
  • B. 均方误差(MSE)
  • C. F1 分数
  • D. R² 分数
解答:F1 分数是精确率和召回率的调和平均,能综合反映模型对少数类的预测能力。准确率在不平衡数据中是误导性指标。

Q2 [单选] SMOTE 算法生成新样本的方式是什么?

  • A. 复制少数类样本
  • B. 在少数类样本之间的连线上进行线性插值
  • C. 添加随机噪声到少数类样本
  • D. 用生成对抗网络(GAN)生成
解答:SMOTE 的核心操作是:对每个少数类样本,找到其最近邻,在两者之间随机插值生成新样本。公式:x_new = x_i + α·(x_nn − x_i)。

Q3 [多选] 以下哪些是处理类别不平衡的有效方法?

  • A. 欠采样(减少多数类)
  • B. 过采样(复制少数类)
  • C. SMOTE(合成少数类样本)
  • D. 代价敏感学习(给少数类更高的误分类代价)
解答:四种都是有效的类别不平衡处理方法。前三种是数据层面方法,第四种是算法层面方法。

Q4 [单选] 随机欠采样的主要缺点是什么?

  • A. 训练时间增加
  • B. 丢弃的多数类样本可能包含重要信息
  • C. 导致类别变得更加不平衡
  • D. 只能用于二分类
解答:随机欠采样简单有效,但丢弃的多数类样本可能包含有价值的模式或子类信息。Tomek Links 和 NearMiss 等方法试图在删除时有选择地保留重要样本。

Q5 [单选] 在极度不平衡(如 1:10000)场景中,以下哪个评估指标最合适?

  • A. 准确率(Accuracy)
  • B. ROC-AUC
  • C. PR-AUC(精确率-召回率曲线下面积)
  • D. 均方误差(MSE)
解答:在极度不平衡场景中,ROC-AUC 可能过于乐观(因为 TN 多导致 FPR 低),PR-AUC 对少数类更敏感,是更好的评估指标。

Q6 [多选] SMOTE 的变体包括哪些?

  • A. Borderline-SMOTE(只在边界生成样本)
  • B. ADASYN(自适应合成采样)
  • C. SMOTE-ENN(生成后用 ENN 清洗)
  • D. SMOTE-CNN(用 CNN 生成样本)
解答:前三项都是 SMOTE 的经典变体。SMOTE-CNN 不是标准变体名称(虽然可以用 GAN 生成样本,但不叫 SMOTE-CNN)。

Q7 [单选] 算法层面的「class_weight='balanced'」是如何工作的?

  • A. 删除多数类样本
  • B. 给少数类分配更高的权重,使损失函数中对少数类错误的惩罚更重
  • C. 复制少数类样本
  • D. 只训练少数类样本
解答:class_weight='balanced' 自动计算各类别的权重(与类别样本数成反比),在损失函数中给少数类样本更高的权重,使模型在优化时更关注少数类。

Q8 [单选] Tomek Links 是什么?

  • A. 一个集成学习算法
  • B. 一对互为最近邻的不同类别样本
  • C. 一个过采样方法
  • D. 一个特征选择方法
解答:Tomek Link 是一对样本 (x_i, x_j),它们属于不同类别且互为最近邻。删除 Tomek Link 中的多数类样本可以清理决策边界,缓解类别不平衡。

Q9 [多选] 关于类别不平衡,以下哪些说法是正确的?

  • A. 准确率高不代表模型好(在不平衡数据中)
  • B. SMOTE 比随机过采样更能防止过拟合
  • C. 组合数据级和算法级方法通常比单一方法效果好
  • D. 类别不平衡对决策树模型没有影响
解答:前三项正确。类别不平衡对所有模型都有影响,决策树也不例外——在不平衡数据上,树的分类边界会偏向多数类。

Q10 [单选] EasyEnsemble 处理类别不平衡的核心思想是什么?

  • A. 使用 SMOTE 生成样本
  • B. 多次欠采样多数类,每次训练一个基分类器,最终集成
  • C. 只使用少数类训练模型
  • D. 给少数类添加噪声
解答:EasyEnsemble 对多数类进行多次独立欠采样,每次与少数类组合训练一个基分类器,最终用 AdaBoost 方式集成。这样既实现了类别平衡,又几乎保留了所有多数类信息。