☰
熵驱动的混合采样集成学习:破解不平衡数据分类难题
2026/10/21 8:18:03 网站建设 项目流程

1. 为什么会去读这篇论文

类别不平衡问题是我在实际项目中经常遇到的硬骨头。比如风控场景里欺诈样本往往只有个位数占比,医疗场景里罕见病阳性样本可能低于1%。常规模型在这种数据下学到的决策边界会严重偏向多数类,少数类被当噪声吞掉,分类报告里precision和recall惨不忍睹。我试过SMOTE、ADASYN这些经典过采样方法,也试过随机欠采样、NearMiss,单用某种采样手段总觉得有局限,过采样容易放大噪声,欠采样则丢失大量多数类信息。

后来在调研集成学习处理不平衡数据的方案时,读到这篇论文——Entropy-based hybrid sampling ensemble learning for imbalanced data。标题里的关键词组合让我很感兴趣:基于熵、混合采样、集成学习,这三个方向各自都有人做,但把熵作为采样策略的核心驱动力、把混合采样和集成框架串成一条完整pipeline的做法并不常见。读完之后,我把自己之前的项目经验跟论文思路做了一次对照重组,收获不小。

这篇笔记会围绕四个问题展开:论文到底处理了什么痛难点、熵为什么能用来指导采样、混合采样和集成是如何协作的、以及这套方法在实际复现和使用中要注意什么。对正在被不平衡数据折磨、又不想无脑套SMOTE的读者,这篇笔记会很有参考价值。同时我还会在复现细节和工程落地上补充一些自己的思考,毕竟论文给的是骨架,真正的坑都在肉里。

2. 不平衡数据处理的整体思路:从研究困境到方法选型

2.1 不平衡问题的困局:数据、算法、评价三层压力

真实场景里的不平衡问题远比“调整一下class_weight”复杂,它有三层压力。

数据层面,少数类样本量过少,模型根本看不到足够多的正例模式;算法层面,传统分类器以整体准确率为优化目标,对多数类天然偏向;评价层面,准确率在不平衡场景下严重失真——99.9%的负例准确率会把模型包装得很好,实则对正类毫无预测能力。这种三重压力叠加,使得单纯调一个参数、换一个损失函数往往很难根治问题。

论文的核心思路是把问题拆成两个阶段——先用数据层面的混合采样把训练分布重新平衡,再用集成学习把多个平衡子集训练的模型组合起来提升泛化稳定性。这正好对应我常说的“先处理好数据,再让模型自己学”,而不是一上来就塞给模型一个畸形的分布。

2.2 已有方案的问题在哪里

按照数据层面处理不平衡问题,传统主流方案大致分三类:过采样、欠采样、混合采样。

过采样(如SMOTE)在少数类样本间插值合成新样本,问题在于容易在重叠区、噪声区生成不合理的样本,边界反而被搞得更模糊。欠采样随机丢弃多数类样本,信息损失严重,模型可能欠拟合;聪明些的欠采样(如NearMiss、Tomek Links)会选“有信息量”的多数类保留,但数量控制不好依然伤筋动骨。混合采样把过采样和欠采样组合使用,思路合理,但怎么判断哪些少数类该过采样、哪些多数类该剔除,许多方法靠距离度量,容易受噪声影响。

论文的切入点很有意思——用熵做判断依据。熵天然适合描述不确定性,一个样本周围类别分布越混乱,熵值越高,说明越可能处于类别重叠区或边界区。这类样本不能简单当成噪声剔除,也不能盲目复制增广,而应该视情况有差别处理。这种“看信息纯度决定怎么采样”的思路,比单纯看距离走得更深一层。

2.3 为什么选择熵和集成框架

读下来我认为论文选择熵和集成框架,至少有三层考虑。

熵提供了一种全局视角的样本质量评估。把样本点映射到其特征领域的不确定性空间后,哪些样本是边界样本、哪些是安全样本、哪些是潜在噪声,可以通过熵值分布直观区分,这和直接用样本间距判断有本质差别:距离近不等于类别不确定,某些局部密度高的区域距离很近但同类纯度很高,不该被过采样。

混合采样解决了单一采样的两种偏向——只过采样会放大少数类噪声,只欠采样会丢失多数类信息。论文用熵把两类操作统一到一个框架里:同一套熵计算逻辑,既找出少数类中值得增广的边界样本,也圈出多数类中熵值异常高的“混乱样本”进行剔除。

集成框架则解决采样随机性带来的偏差。单次采样生成的训练集只是原分布的一个有偏估计,用Bagging的思路多次采样生成多个平衡子集,每个子集训练一个基分类器再聚合,各样本被充分使用,分类器方差被压低。整个pipeline的逻辑链条是:熵找重点样本,混合采样制造平衡视图,集成提升稳定性。

3. 论文方法核心细节解构

3.1 熵在样本层面怎么计算

论文使用熵来度量一个样本在其邻居集合中的类别不确定程度。对于某个样本x,取其k个最近邻(通常用欧氏距离),统计这些近邻中各类别的占比。设第j类样本数占k个近邻的比例为p_j,则样本x的熵值为:

H(x) = -sum(p_j * log(p_j))

如果k个近邻全都是同一类别,熵接近0,说明该样本处于同类聚集区,类别确定性很高。如果k个近邻中各类占比接近均等,熵接近log(C)(C为类别数),说明该样本正处于类别交错地带,不确定性达到峰值。约化为二分类问题时,熵值在0到log2之间变化,实操中常归一化到0到1区间,方便跨数据集对比。

从信息论的角度看,熵值高的地方正好蕴含模型最需要的判别信息——如果某个区域类别分布完全均匀,在这个区域里随便划分,错误率都差不多,决策边界必然在这里;反过来说,远离边界的同类密集区,模型不容易错,但也没太多区分度。

3.2 样本分区的逻辑

作者以熵值高低把训练样本划为三个区:

安全区样本熵值很低。少数类中的安全区样本远离多数类,是“根正苗红”的代表性样本,不需要额外加工。多数类中的安全区样本也有价值,但在欠采样时可以优先考虑这部分。

边界区样本熵值中等偏高。这里最需要干预。少数类边界样本是少数类与多数类“抢地盘”的关键力量,对这类样本执行过采样(合成新样本),等于沿着边界线增强少数类密度,迫使模型更精细地学习决策边界。

噪声区样本熵值极高。这类样本周围近邻类别严重混杂,可能是标注错误,也可能是极端离群点。对少数类噪声样本,如果强行过采样,会不断放大错误信息。对多数类噪声样本,论文倾向剔除。这里有个关键处理差异:对少数类中的高熵样本,不是简单剔除或保留,而是结合信息量判断,若其周围仍有部分同类的证据支撑,则保留但不增广;若是完全被多数类包围,则视为噪声,排除采样范围。

3.3 混合采样策略的完整流程

具体流程可按以下步骤拆解:

输入:原始不平衡训练集D;近邻参数k;采样倍率N;基分类器数量T 输出:T个平衡训练子集

  1. 对每个样本计算近邻类别分布,进而计算熵值H(x);

  2. 根据熵分布选择阈值,划分三个样本区域;

  3. 对少数类边界区样本执行基于熵加权的过采样——熵越高,生成样本时注入轻微扰动并增加合成数量;

  4. 对多数类噪声区样本执行欠采样——按熵排序,优先剔除熵最高的样本,直到多数类数量与少数类接近;

  5. 在一次采样过程中,获得一个类别比例接近1:1的训练子集;

  6. 重复步骤3—5共T次,生成T个有差异但保底平衡的子集;

  7. 分别在T个子集上训练基分类器;

  8. 新样本输入时,综合所有基分类器的预测结果进行投票。

你能看到,这个流程跟传统单一采样最大的不同是“边采样边看质量”——在过采样和欠采样过程中都嵌入了熵判断,不是机械地合成或丢弃。

3.4 为什么这个方法能互补

过采样和欠采样的误区通常来自“用错地方”。SMOTE逻辑简单,用好就好,用坏就糟:如果原始少数类本身存在较多噪声样本,SMOTE在噪声之间也插值,大量合成的“伪少数类样本”反而干扰模型。

论文把高熵样本先筛出来,过采样只针对边界区少数类,噪声区少数类被排除在合成池之外。同时多数类中高熵样本被剔除,等于把最容易混淆的那部分多数类移走。一个做加法,一个做减法,但两个减法都对在“熵最高”的样本上。边界区的少数类过采样后密度增加,噪声区的多数类被清除后边界干净,模型得到的正负类分布变形更健康。

集成部分解决的是单次采样可能产生的“偏见子集”。每次采样都会带走或合成一批样本,训练集必然与原分布不同,单一模型可能会把采样偏差学进去。论文用集成把这种偏差分散——每个基分类器在略有差异的平衡子集上学习,投票时各分类器的偏向被平均,整体预测更稳。

4. 模型设计里的关键取舍与操作细节

4.1 熵阈值怎么定

论文中确定熵阈值的方式是计算全部少数类样本熵值后,取中位数和四分位数作为参考,同时根据多数类区域边界密度做微调。由于不同数据集的近邻分布差异大,阈值不固定反而更合理。实操中我建议先用局部熵分布做可视化——画出熵直方图,看是否存在明显双峰,如果有,谷底就是天然阈值;如果单峰,可以按熵排序取前20%作为高熵区,后40%作为安全区。本地做一次敏感性测试即可,“数据分布不同,阈值跟着走”比“全局参数硬套”更靠谱。

4.2 近邻k值的影响

k值在熵计算中决定“视野”大小。k太小,熵值波动大,很容易把密集区的正常样本标的很高;k太大,熵值平滑过头,边界区被模糊掉。论文实验覆盖了k取5、7、10等多种设置,团队自己实验的结果是k=5到7在多数数据集上表现较稳。考虑到少数类总量往往不多,指数级增大k会直接压低少数类的熵区分度,我建议二分类问题从k=5开始调。多分类问题若样本充足可以尝试k=10。

4.3 基分类器的选择

论文实验对比了决策树、SVM、kNN等基分类器,最终采用的方案在多数数据集上都优于单分类器搭配同类采样。从原理上解释,决策树类模型对特征尺度不敏感,能天然适应采样后分布的巨大变化;同时集成思想本来就要求基分类器“好而不同”,决策树的随机性恰好满足差异化的需求。我推荐复现时基分类器直接用决策树,把集成个数T设为10—20之间,树的深度限制在合理范围。SVM做基分类器在小数据集上效果也不差,但训练成本高,大数据量不推荐。

4.4 采样倍率与“平衡”到底要平衡到什么程度

很多初学者以为采样后必须严格1:1才算平衡。论文的实验和我的项目经验都反复验证:不一定。严格1:1在部分场景会过度压缩多数类(信息损失)或过度合成少数类(噪声增长)。更稳健的选择是让少数类与多数类的训练样本比例落在1:1到1:3之间,甚至在多数类远多于少数类时放宽到1:5,效果反而更好。

论文中的采样倍率N需要根据实际目标调整:如果重在recall(比如罕见病筛查),略微过采样少数类能拉高少数类灵敏度,此时建议比例偏向1.2:1;如果要求整体准确率稳定,1:2或1:3更折中。关键是务必在验证集上做比例扫描,而不是盲目追求数学对称。

4.5 数据泄漏问题

使用任何过采样类方法都必须把采样过程放到交叉验证内部进行。这个问题值得特别强调:如果在划分训练集和测试集之前就整体过采样,合成的少数类样本很可能与测试集样本来自同一区域,导致验证结果虚高,上线后性能直线缩水。正确做法是每一个折内单独执行“计算熵值—确定样本分区—做混合采样—训练模型”的完整流程,测试集只用来评估。论文实验部分虽然没有详细展开这点,但这是工程落地环节最容易被忽视的细节,也往往是复现结果“和论文对不上”的罪魁祸首。

5. 实验设计观察与数据集表现解读

5.1 论文实验设置特点

论文采用的是多组不平衡二分类数据集进行验证,指标上主看G-mean(几何均值)和AUC,辅助看F1。选G-mean和AUC很有讲究:G-mean同时考虑少数类和多数类的召回,能直观反映两类均衡程度;AUC不依赖概率阈值,能评估模型对正负样本的排序能力。F1偏重少数类精确率和召回率的折中,但在极度不平衡时对阈值敏感,所以做主指标容易失真。我们项目里也延续了这套指标组合,G-mean在风控评分卡场景中比准确率有用得多。

5.2 方法对比的几条主线

论文对比了四种典型方案:单独过采样(SMOTE及其变体)、单独欠采样(随机欠采样、EasyEnsemble)、其他混合采样方法,以及算法层面方法(代价敏感学习)。结果呈现出的规律与我个人实验体验一致:

熵混合采样集成的优势在中等不平衡比例(1:10到1:100)时最强,这时边界区信息还够用,混合采样的价值最大;在极度不平衡(1:1000)时,边界区少数类本身太少,熵估计噪声变大,方法优势有所收窄。在与代价敏感学习对比时,纯算法层面方法在损失函数上做文章,不需要改数据,但对复杂分布适应力弱。熵混合采样从数据源头改变分布,和模型选择天然解耦,灵活性高。

5.3 结果表象之外的启示

实验表格里更值得关注的是方差指标——作者统计了多次重复实验的标准差。混合采样加上集成框架,分类器性能的方差显著低于单次采样再训练的方法。这说明采样随机性和模型不稳定性同时被压住了。这一点对真实项目很重要:单次采样可能运气好得到一个漂亮分数,但上线后波动大;集成框架牺牲少量算力,换到的是更可靠的均值表现。

6. 复现要点与工程实践经验

6.1 复现时的代码框架

以下是我基于论文思路整理出的一个可运行框架,配套注释方便按步骤搭建:

import numpy as np from sklearn.neighbors import NearestNeighbors from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import VotingClassifier def compute_entropy(X, y, k=5): neighbors = NearestNeighbors(n_neighbors=k).fit(X) _, indices = neighbors.kneighbors(X) entropy = [] for i in range(len(X)): labels = y[indices[i]] probs = np.bincount(labels, minlength=2) / k entropy.append(-np.sum(probs * np.log(probs + 1e-9))) return np.array(entropy) def hybrid_sample(X, y, entropy, n_ratio=2): majority = X[y == 0]; minority = X[y == 1] ent_min = entropy[y == 1]; ent_maj = entropy[y == 0] # 用熵筛选 border_idx = ent_min > np.median(ent_min) noise_idx = ent_maj > np.percentile(ent_maj, 70) X_syn, y_syn = [], [] for idx in border_idx: for _ in range(n_ratio): # 使用简单插值,选最近邻中点生成新样本 neighbor = np.random.choice(k) X_syn.append(minority[idx] + 0.1 * (minority[neighbor] - minority[idx])) y_syn.append(1) X_maj_kept = majority[~noise_idx] X_bal = np.vstack([np.array(X_syn), X_maj_kept, minority]) y_bal = np.hstack([np.array(y_syn), np.zeros(len(X_maj_kept)), np.ones(len(minority))]) return X_bal, y_bal # 集成循环 estimators = [] for t in range(10): X_bal, y_bal = hybrid_sample(X_train, y_train, entropy_train) clf = DecisionTreeClassifier(max_depth=8) clf.fit(X_bal, y_bal) estimators.append(('tree_' + str(t), clf)) ensemble = VotingClassifier(estimators, voting='soft') ensemble.fit(X_train, y_train)

这段代码把核心流程压缩在100行以内,细节还可以根据数据情况调整。注意几个地方:熵的计算用NN索引直接做,效率高;合成样本时不直接复制而是做轻微插值,符合论文“边采样边增广”的思路;欠采样保留多数类的安全区与部分边界区,避免信息断崖。工程上还可以把这段逻辑封装成sklearn风格的transformer组件,方便塞进pipeline。

6.2 项目中使用时的步骤建议

落地这套方法不必一步到位,我的建议是渐进式三阶段:

第一阶段,跑通基线。先用原始数据训练一个分类器,记录G-mean、AUC、F1的基线值,同时熟悉数据中的不平衡比例和特征分布。

第二阶段,对照验证。在同样模型结构下使用单一SMOTE、单一随机欠采样、论文的熵混合采样,三组结果放一起比对。这样能直观看到混合采样到底比单一采样多了什么优势,也能确认值得增加的计算开销是否落到实绩上。

第三阶段,针对性调优。调节三个关键杠杆:熵分区的阈值(第60%到80%分位可以扫描)、采样倍率N(1到3之间扫)、基分类器数量T(10到30之间扫)。调参的过程中务必保留验证脚本,方便快速循环。

6.3 这套方法在真实业务场景中的适配性

从我的落地经验看,该方法最适合“少数类有一定样本量但不至于太少”的场景,比如金融反欺诈(欺诈率约1%—5%)、工业生产中的故障检测(故障率约2%—10%)、电商的异常点击识别。异常点击和二分类场景下,熵混合采样既能撑住少数类召回,又不至于像纯过采样那样把正常模式搞乱。

如果是极端稀疏的场景(比如正样本不足50条),建议先尝试迁移学习或预训练,再考虑采样增广,否则熵计算本身可能不稳定。如果是高维稀疏特征(比如文本TF-IDF),欧氏距离的可靠性要打折扣,建议在嵌入空间或降维空间做采样,同时仔细验证熵计算是否还具判别力。

6.4 常用数据处理与基线方法对比速查表

为了方便回顾,我把这套方案和其他常见方法放在一张表里对比:

方法核心思想优势劣势适用场景
SMOTE过采样少数类插值合成实现简单,通用性强噪声放大,边界模糊少数类聚团明显
随机欠采样随机删除多数类计算开销小信息损失严重数据量极大
代价敏感学习调整损失权重不改数据分布对复杂分布欠适应,阈值难调类别不平衡中等
熵混合采样集成熵驱动分区+混合采样+Bagging边界干净,方差小,通用性好计算量较大,参数较多中等不平衡,边界样本存在

这张表的用意不是给方法排名,而是帮助读者根据业务优先级做取舍。如果你每周要跑数千个模型,计算功率有限,随机欠采样可能是更务实的选择;如果你更在意少数类的开会和稳定预测,熵混合采样集成的价值就体现出来了。

7. 常见问题与避坑经验

7.1 熵值分布不是双峰怎么办

很多人在复现时照搬论文的“按熵值分安全/边界/噪声”思路,结果发现自己的数据集熵值集中在0.6附近,没有一个自然的波谷,分区无从做起。我的经验分成两条:如果数据密度高,熵值整体偏高,分区阈值直接按分位数走,不追求“物理意义”;如果是少数类太少导致局部熵估计不稳,先增加k或者用核密度估计平滑局部熵,再执行分区。追根究底,熵分区的本质是把样本按混淆程度排序,有没有波谷不影响排序的价值。

7.2 合成样本导致过拟合怎么办

过采样方法几乎都逃不掉的一个抱怨是“合成样本干扰太大,模型反而变差”。这种情况通常有两个原因:一是选择边界区合成参数不当,合成样本离原有样本太近,相当于复制粘贴,模型记忆了个案;二是合成噪音本身已脱离真实分布。建议在合成时增加“过采样安全Margin”,即限定新样本点必须落在少数类k近邻张成的适度半径内,而不是任意插值。同时注意控制合成总量,过采样后的总算个数不宜超过多数类保留量的1.5倍,不然边界重塑过头,模型会把某些合成区域当成硬边界,导致真实推理时误判。

7.3 基分类器一定用决策树吗

论文的默认基分类器是决策树,但这个选择不等于在所有场景都最优。如果你的特征是稀疏高维的,决策树很容易被无关特征带偏,建议换成逻辑回归或线性SVM,此时采样后的平衡数据依然能提升模型整体效果。如果你的特征是图像、语音类高维稠密特征,决策树能力有限,可以把基分类器换为浅层神经网络,集成策略不变。退化现象很少见,但需要留意。

7.4 训练变慢怎么优化

集成本身就是要训练T个分类器,计算量乘以T,确实比单模型慢不少。两招缓解:一是并行化,集成天然可并行,用Joblib或线程池把基分类器训练分散到多个核心;二是T减小到5—8,用投票机制保证基本稳定性即可,树模型有随机性支持,T在5以上差异就很小了。此外,可以先用少量数据调试全流程,确认管道无误后再全量跑。

7.5 做风险预测时正类样本纯度很低怎么办

如果少数类本身包含很多噪声标注(比如欺诈样本里混了正常用户的误标记),熵值计算会把某些噪声的少数类样本划入高熵区,过采样时这些错误信息会被放大。这时可以加一道人工校验:在生成的新样本中检查是否出现跨类交叉点,如果合成的少数类样本和多数类距离过近,丢弃并重新生成。在业务异常检测中,还建议输出每个样本的熵值作为辅助解释字段,这样风控人员能看到哪些样本被模型认为是高混淆区域,为后续人工复核提供线索。

8. 个人对这套方案的扩展思考

读完这篇论文,我的最大感触是:它的价值不在于给了一个固定的采样公式,而在于提供了一个新的视角——把信息量度量嵌入数据预处理流程。同样的思路可以延展到更多场景里。

第一个扩展方向是“熵+代价敏感”的串联。熵可以指出样本的困难程度,代价敏感学习可以调节损失权重,二者并不冲突。在训练时把熵值作为样本权重的一项参考,高熵样本在损失函数里天然权重更大,这相当于在数据层面和损失层面做了双重修正。第二个扩展方向是和数据清洗结合。很多业务数据存在噪声,采集过程的脏数据混在训练集里。熵值可以作为质量分,把清洗环节从“凭经验删”变成“用不确定性排序删”。第三个扩展方向是动态重采样——在训练过程中,每个epoch重新计算当前模型下的样本熵,进而动态调整采样分布,相当于把混合采样从离线搬到在线,也许能进一步提高泛化。

9. 最后的实操心得

我在自己项目里复现这套方法时,真正踩到的最大坑就是交叉验证分隔问题。一开始偷懒直接对整个数据集采样再分开训练测试,结果G-mean虚高好几个点,上线后缩水严重。重构成“每折内部独立采样”之后结果才慢慢和论文趋势靠拢。这里也想再次提醒,无论你用什么采样方法,管线顺序千万别搞反。

另一条心得和参数相关。真去扫一轮阈值和比例,你会发现论文给的经验值只能当起点,不是终点。数据分布一变,最优点就漂移,用一个留出验证集快速扫描三四个配置,选一个最稳的,比陷入“理论调参”要快得多。熵计算用现成库只需要几行代码,计算熵分布的直方图多看几遍,数据长什么样子心里有数了,方法就好用了。

这篇论文笔记写到这里基本把我认为值得记录的内容都覆盖了。方法本身不是特别复杂,但它在“采样策略要和样本不确定性挂钩”这个点上做得特别彻底,非常值得正在做类别不平衡任务的从业者花时间读一读原论文、在自己的数据上跑一版对比。相信你跑通之后,会对“不平衡数据处理”这件事有一个更整体的认知——它不再是生硬套用SMOTE或者调整class_weight的技术动作,而是数据质量、分布观察和模型设计三者妥协平衡的系统工程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询