在许多实际的文本分类情境中,你可能会遇到类别分布很不均匀的数据集。设想构建一个垃圾邮件过滤器:多数邮件可能是合法的(非垃圾邮件),而只有很少一部分是垃圾邮件。类似地,医疗文件分类可能涉及大量常规报告,而极少部分指向罕见病症。这些情形导致不平衡数据集,其中一个或多个类别(少数类别)与其它类别(多数类别)相比,样本数量明显偏少。为什么这种不平衡是个问题呢?标准的机器学习算法,通常旨在优化整体准确率,往往会对多数类别产生偏向。一个模型可能仅仅通过总是预测多数类别就能达到高准确率,从而实际上忽略了少数类别。当少数类别是你最感兴趣识别的(例如,欺诈交易、紧急支持工单、罕见疾病指标)时,这个问题尤其突出。此外,如评估指标部分所述,整体准确率在不平衡数据集上可能是一个误导性指标。一个分类器正确识别95%的邮件可能听起来不错,但如果只有5%是垃圾邮件,那么一个将所有邮件标记为非垃圾邮件的模型仍然能达到95%的准确率,但对于垃圾邮件检测来说却完全没用。识别类别不平衡第一步是辨别你是否在处理一个不平衡数据集。这通常很简单:查看训练数据中目标标签的频率分布。你可以使用简单的计数或直方图、条形图等可视化方式来查看比例。{"data":[{"type":"bar","x":["非垃圾邮件","垃圾邮件"],"y":[9500,500],"marker":{"color":["#4dabf7","#fa5252"]}}],"layout":{"title":{"text":"类别分布示例:垃圾邮件检测","x":0.5},"xaxis":{"title":"邮件类别"},"yaxis":{"title":"邮件数量"},"bargap":0.2}}垃圾邮件检测数据集中典型的非平衡分布。如果你发现显著的偏斜,即一个类别明显多于其他类别(例如,比例为10:1、100:1或更高),你需要考虑应对方案,以减轻对分类器性能的潜在负面影响,特别是针对少数类别的召回率和F1分数等指标。高整体准确率可能掩盖了你最关注的类别的极低召回率。处理不平衡数据的方法有几种技术可以帮助处理文本分类中不平衡数据集带来的难题。这些方法通常分为数据层面的方法(修改数据集)和算法层面的方法(修改学习算法)。数据重采样技术重采样是指调整训练数据中的类别分布,以创建一个更平衡的数据集供模型学习。进行重采样只应在训练数据上,绝不能在验证集或测试集上进行,以确保评估的公正性。少数类别过采样: 这涉及增加少数类别实例的数量。随机过采样: 最简单的方法是随机复制少数类别的样本。虽然易于实现,但可能导致过拟合,因为模型可能从重复的实例中学习到特定模式,而不是很好地泛化。合成少数类别过采样技术 (SMOTE): SMOTE是一种更精巧的方法。SMOTE不是简单地复制现有实例,而是在特征空间中生成新的合成样本。它的工作方式是选择一个少数类别实例,找到其k个最近邻居(也来自少数类别),然后在连接该实例及其邻居的线段上创建合成点。这通常比简单的随机过采样能带来更好的泛化能力。Python中的imbalanced-learn等库提供了SMOTE及其变体的实现。多数类别欠采样: 这涉及减少多数类别实例的数量。随机欠采样: 从多数类别中随机移除实例,直到达到更平衡的分布。主要缺点是可能丢失被移除实例中包含的有价值信息,如果数据集本来就很小,这可能会造成不利影响。智能欠采样: 像Tomek Links或Edited Nearest Neighbors (ENN)这样的技术尝试更具选择性。例如,Tomek Links识别来自不同类别的、互为最近邻居的实例对;移除这些对中的多数类别实例有助于清理类别边界。结合过采样和欠采样: 有时,结合多种方法效果最佳。例如,你可能对少数类别进行适度水平的SMOTE,并对多数类别进行一些随机欠采样,以达到平衡状态,而不会过度扭曲原始数据特征。算法方法:成本敏感学习除了修改数据,你还可以调整学习算法,使其更关注少数类别。这被称为成本敏感学习。核心想法是,对少数类别上发生的错误赋予比多数类别上发生的错误更高的误分类成本。训练时,算法会尝试最小化总成本,从而有效促使其更细致地学习少数类别中的模式。许多分类算法,包括逻辑回归、支持向量机和基于树的方法,都提供了处理类别权重的参数。例如,在scikit-learn中,你通常可以将class_weight参数设置为'balanced'。此模式会自动调整权重,使其与输入数据中的类别频率成反比:$$ w_j = \frac{n_{samples}}{n_{classes} \times n_{samples_j}} $$其中 $w_j$ 是类别 $j$ 的权重,$n_{samples}$ 是样本总数,$n_{classes}$ 是类别数量,$n_{samples_j}$ 是类别 $j$ 中的样本数量。选择合适的评估指标如前所述,准确率对于不平衡问题往往不足。仅仅依赖它可能导致你部署一个在原定任务上表现不佳的模型。相反,应侧重于那些能更好反映不同类别(特别是少数类别)性能的指标:混淆矩阵: 始终检查混淆矩阵,以查看每个类别的正确和错误预测的分布(真阳性、真阴性、假阳性、假阴性)。精确率、召回率、F1分数: 密切关注这些指标,特别是针对少数类别。召回率(敏感度或真阳性率)通常很重要,因为它衡量模型识别正实例的能力。F1分数则在精确率和召回率之间提供平衡。精确率-召回率曲线 (PRC) 和曲线下面积 (AUC-PR): 与ROC曲线不同,PR曲线对于高度不平衡的数据集更有参考价值,因为它侧重于少数(正)类别的性能。AUC-PR概括了这条曲线。实践注意事项将重采样技术整合到模型训练流程中时,尤其在使用交叉验证时,绝对需要在交叉验证循环的每个折叠内部应用重采样步骤,并且只使用该折叠的训练部分。如果在交叉验证数据分割之前应用重采样,会导致数据泄露,即验证折叠中的信息影响训练过程,从而导致过于乐观和不切实际的性能评估。digraph ResamplingPipeline { rankdir=LR; node [shape=box, style=rounded, fontname="helvetica"]; edge [fontname="helvetica"]; RawData [label="原始训练数据"]; Split [label="分割成 K 折", shape= Mdiamond]; subgraph cluster_fold { label = "对于每个折叠 i:"; style=dashed; TrainData [label="训练数据 (折叠 != i)"]; ValData [label="验证数据 (折叠 i)"]; Resample [label="应用重采样\n(例如,SMOTE,欠采样)"]; TrainModel [label="训练分类器"]; Evaluate [label="在验证数据上\n评估"]; TrainData -> Resample [label="1."]; Resample -> TrainModel [label="2."]; TrainModel -> Evaluate [label="3."]; ValData -> Evaluate [label="原始数据\n(不重采样)"]; } Aggregate [label="汇总结果\n(来自 K 折)"]; RawData -> Split; Split -> TrainData; Split -> ValData; Evaluate -> Aggregate; }在交叉验证循环中应用重采样的正确流程。重采样仅应用于每个折叠的训练部分。选择最佳方法通常需要进行实验。没有一种方法是普遍优越的。过采样、欠采样或成本敏感学习的有效性取决于特定的数据集、不平衡程度、所选的分类算法以及你优先考虑的评估指标。首先识别不平衡情况,选择合适的指标,然后尝试一种或多种技术,使用交叉验证等验证方案仔细评估对少数类别性能的影响。处理数据不平衡通常是构建实际有用的文本分类器的必要一步。