6月4日 11:03

NLP 数据不平衡怎么处理?重采样、Focal Loss 和评估指标详解

数据不平衡的核心问题:模型倾向于预测多数类,因为这样做在训练集上损失最低。比如 95% 正面 + 5% 负面的情感数据,模型全猜正面也有 95% 准确率——但负面的召回率是 0。

解决思路分三层:数据层(调整样本分布)、算法层(调整学习过程)、评估层(选对指标)。

数据层:重采样

过采样:复制少数类样本。最简单的是随机复制,但容易过拟合——模型反复看到同样的样本。NLP 里更好的做法是回译(中文翻英文再翻回来,得到语义相同但表达不同的新样本)和同义词替换,这比 SMOTE 在文本上更自然。

欠采样:随机丢弃多数类样本。数据量大时有效,但可能丢掉有用信息。折中方案是 EasyEnsemble:对多数类做多次不同的欠采样,每次训练一个子模型,最后集成投票——既不丢信息也不偏多数类。

算法层:损失函数调整

类别加权:给少数类的损失乘一个更大的权重,公式 weight_i = N / (C × n_i),让模型在少数类上犯错代价更高。PyTorch 里 CrossEntropyLoss(weight=torch.tensor([0.5, 10.0])) 一行搞定。

Focal Loss:比加权更聪明。它自动降低"容易分对的样本"的权重,把训练精力集中在难分的样本上:FL = -α(1-p_t)^γ log(p_t)。γ=2 时,一个已经 p=0.9 分对的样本,损失会被压到原来的 1%,模型基本不理它。目标检测里先火起来的,NLP 不平衡分类也适用。

评估层:别看准确率

不平衡数据下准确率完全误导。F1 分数(精确率和召回率的调和平均)是基本盘。如果更关心少数类不被漏掉,看 召回率;如果更关心少数类预测的准确性,看 精确率AUC-PR 比 AUC-ROC 更适合极端不平衡场景,因为 ROC 在负例远多于正例时过于乐观。

python
from sklearn.metrics import classification_report # 别只看 accuracy,看每个类的 precision/recall/f1 print(classification_report(y_true, y_pred))

实际怎么选方案

先试最简单的:类别加权 + F1 评估,10 分钟能跑完。效果不够再加数据增强(回译最省事)。还不行上 Focal Loss。再不行就 EasyEnsemble 集成。别一上来就堆复杂方法——大多数场景类别加权就够了。

一个容易忽略的点:验证集不要做重采样。训练集可以过采样/欠采样,但验证集和测试集必须保持原始分布,否则评估结果不可信。

标签:NLP