跳至主要内容

深入探讨失衡数据

学习处理类别分布不均数据集的技术。
· 14分钟 阅读

使用 AI 探索

请考虑以下情境——

您在处理一个数据集。您构建了一个分类模型,并立即获得了 90% 的准确率。结果看起来相当惊艳。可当您再深入一点,就会发现几乎所有数据都属于同一类。糟糕!类别失衡会让人非常挫败。

当您发现数据存在类别失衡,原以为很棒的结果其实靠不住时,难免沮丧。而更让人沮丧的是,许多不错的书籍也很少系统地讨论这个主题。

这正是由类别失衡数据集引发的情形,以及它可能带来的令人抓狂的结果。

在本教程中,您将了解一系列可用于在失衡数据集上取得优异结果的技术。具体包括:

  • 什么是失衡数据?
  • 为什么失衡数据集是个严峻的问题?
  • 准确率悖论
  • 分类器评估的不同指标
  • 处理失衡数据的多种方法
  • 该主题的延伸阅读

先来看看什么是失衡数据。

target distribution 来源:KDNuggets

What is Imbalanced Data?

失衡数据通常是指分类任务中,不同类别的样本数量不均衡。

例如,您有一个二分类问题,共 100 个样本,其中 80 个标记为 Class-1,剩余 20 个标记为 Class-2。

这就是一个失衡数据集的典型例子,Class-1 与 Class-2 的样本比为 4:1。

无论是 Kaggle 竞赛还是实际测试数据,类别失衡都是最常见的问题之一。

大多数真实世界的分类任务都或多或少存在类别失衡:对应某些类别标签的数据量不足。因此,必须正确选择模型的评估指标。否则,您可能会去调整/优化一个无用的参数。在以业务为先的场景中,这可能导致彻底的浪费。

有些问题类别失衡不仅常见,而且几乎必然发生。比如,涉及欺诈与非欺诈交易的数据集,欺诈交易的数量很可能远少于非欺诈交易。这就是问题的根源所在。接下来您会看到原因。

Why are Imbalanced Datasets a Serious Problem to Tackle?

尽管众多机器学习算法(包括深度与统计方法)在很多实际应用中都很成功,但从失衡数据中学习仍未达到最先进的水平。通常,从失衡数据学习被称为Imbalanced learning(失衡学习)。

失衡学习的主要问题包括:

  • 当数据集中存在代表性不足的数据时,类别分布会出现偏斜。
  • 由于数据本身的复杂特性,要从这类数据中学习需要新的理解、方法、原则与数据变换工具。此外,这也并不保证能高效解决业务问题。最糟的情况下,可能完全无用且无任何可复用的产出。

此时您可能会问:在 GPU、TPU 如此发达的时代,为什么机器学习算法仍难以高效处理失衡数据?这是个很自然的问题,答案如下。

机器学习算法的评估方式,很大程度上决定了算法在面对失衡数据时为何表现不佳。

“当准确率指标显示您拥有出色的准确率(比如 90%)时,实际它只是在反映底层的类别分布。”——Machine Learning Mastery

假设您有一个二分类数据集,类别分布比为 9:1。总样本数为 1000,类别标签为 Class-1 与 Class-2。根据分布比,Class-1 有 900 个样本,Class-2 有 100 个。您使用一个标准分类器(如逻辑回归),并用分类准确率来评估(即被正确分类的样本数占比)。现在仔细想一想。

您的逻辑回归模型其实不必复杂,就能把全部 1000 个样本都预测为 Class-1。这样得到 90% 的准确率,但这显然不足以衡量分类器的真实质量。很明显,您需要其他指标来评估系统性能。您马上就会看到。这种现象称为准确率悖论。

Approaches for Handling Imbalanced Data:

本节先从几种非“分类准确率”的指标开始,以便在处理失衡数据时,能够更真实地评判分类器。

首先定义四个基本概念:

  • 真正类(TP)——正类样本被正确分类为正类
  • 真负类(TN)——负类样本被正确分类为负类
  • 假正类(FP)——负类样本被错误分类为正类
  • 假负类(FN)——正类样本被错误分类为负类

下图可以说明上述术语:

terms table 来源

现在,假设您在刚才的玩具数据集上训练了另一种分类器,这次使用随机森林,得到 70% 的分类准确率。既然您已了解真正率、真负率与假正率、假负率,接下来更细致地比较此前的逻辑回归与随机森林。

假设逻辑回归的真正率、真负率与假正率、假负率如下所示:

logistic regression rates

再假设随机森林的这些指标如下:

random forest rates

看看两个分类器对负类的正确预测数量(真负类)。在失衡数据集上,您需要优先关注这个数值(因为数据集中 Class-1 占主导)。在此意义上,随机森林明显优于逻辑回归。

现在,您已准备好学习应对失衡数据集问题的具体方法。

(注意,上述表示方式通常称为混淆矩阵。)

以下两项指标源自混淆矩阵,评估分类器时非常常用。

精确率(Precision):精确率等于真正类数除以真正类与假正类之和。换言之,即正类预测数除以所有被预测为正类的总数。也称为正预测值(PPV)。

精确率可被视为分类器的“严谨度”。精确率低通常意味着假正类多。

召回率(Recall):召回率等于真正类数除以真正类与假负类之和。换言之,即正类预测数除以测试数据中真实正类的数量。也称为灵敏度或真正类率。

召回率可被视为分类器的“完整度”。召回率低通常意味着假负类多。

其他可能有用的指标:

在学习处理类别失衡的方法之前,先看一个非常真实的例子:如果只选择分类准确率作为评估指标,可能会导致糟糕的结果。(目的是确保您在训练下一个分类器时,不只看准确率。)

乳腺癌数据集是一个标准的机器学习数据集。它包含 9 个特征,描述了 286 位曾罹患并存活的乳腺癌患者,以及其是否在 5 年内复发。让我们基于该数据集直观感受一下问题。

该数据集是一个二分类问题。在 286 位女性中,201 位未复发,剩下 85 位出现复发。

让我们用可视化的方式进一步探索该数据集。

import numpy as np
import pandas as pd

# Load the dataset into a pandas dataframe
data = pd.read_csv("breast-cancer.data",header=None)

# See the data
print(data.head(10))
                      0      1        2      3    4   5  6      7          8  \
0  no-recurrence-events  30-39  premeno  30-34  0-2  no  3   left   left_low   
1  no-recurrence-events  40-49  premeno  20-24  0-2  no  2  right   right_up   
2  no-recurrence-events  40-49  premeno  20-24  0-2  no  2   left   left_low   
3  no-recurrence-events  60-69     ge40  15-19  0-2  no  2  right    left_up   
4  no-recurrence-events  40-49  premeno    0-4  0-2  no  2  right  right_low   
5  no-recurrence-events  60-69     ge40  15-19  0-2  no  2   left   left_low   
6  no-recurrence-events  50-59  premeno  25-29  0-2  no  2   left   left_low   
7  no-recurrence-events  60-69     ge40  20-24  0-2  no  1   left   left_low   
8  no-recurrence-events  40-49  premeno  50-54  0-2  no  2   left   left_low   
9  no-recurrence-events  40-49  premeno  20-24  0-2  no  2  right    left_up   

    9  
0  no  
1  no  
2  no  
3  no  
4  no  
5  no  
6  no  
7  no  
8  no  
9  no  

列名是数字,因为这里用的是部分预处理后的数据集。如果您感兴趣,可以参考下图:

来源

我们绘制类别分布的柱状图。

import matplotlib.pyplot as plt

classes = data[9].values
unique, counts = np.unique(classes, return_counts=True)

plt.bar(unique,counts)
plt.title('Class Frequency')
plt.xlabel('Class')
plt.ylabel('Frequency')
plt.show()
class frequency chart

您可以清楚地看到类别失衡。yes 表示患有癌症的样本,显然,与另一类相比,这类样本的数量要少得多。

让我们定义数据集中出现的“未复发(No Recurrences)”与“复发(Recurrences)”,以便更清晰。

  • 全为未复发:如果一个模型只预测“未复发”,其准确率为 (201/286) × 100,即 70.28%。这称为全为未复发。准确率看似很高,但模型很糟。如果误读了该模型,将有 85 位女性被错误告知其乳腺癌不会复发(高假负)。

  • 全为复发:如果一个模型只预测“复发”,其准确率为 (85/286) × 100,即 29.72%。这称为全为复发。该模型准确率低下,会让 201 位女性误以为发生了复发,但事实并非如此(高假正)。

看到这里,您应该已经有所触动。继续往下看。

现在,您已经有充分理由认识到,仅用分类准确率来评估模型并非明智之选。

接下来学习一些方法。

Re-sampling the dataset:

处理失衡数据集的策略包括:改进分类算法,或在将数据输入算法前(本质是数据预处理步骤)对训练数据中的各类样本进行平衡。后者更为常用且适用范围更广。而且,相比改进算法,生成所需样本通常更省时。但在研究场景下,两者都值得探索。

采样的核心思想是:要么增加少数类样本,要么减少多数类样本。目的是让两类样本数量达到更合理的平衡。

主要有两类采样方法:

  • 向少数类添加样本副本,称为过采样(更正式地说是有放回采样);或
  • 从多数类中删除样本,称为欠采样。

从实现角度看,这似乎也并不复杂,是吧?稍后您会了解到一个专门用于采样的库。

Random under-sampling:

当您随机从数据集的多数类中删除样本,并将其分配给少数类(且不填补多数类因此产生的“空缺”)时,称为随机欠采样。由于多数类中留下了“空缺”,这个过程具有随机性。

优点:

  • 当训练集非常庞大时,减少训练样本数量有助于提升模型运行效率并缓解内存问题。

缺点:

  • 可能丢弃对数据本身有用的信息,而这些信息可能对构建基于规则的分类器(如随机森林)很重要。
  • 随机欠采样得到的样本可能存在偏差,无法准确代表总体,从而导致分类器在未见过的数据上表现不佳。

Random over-sampling:

与随机欠采样类似,也可以进行随机过采样。但在这种情况下,不从多数类“借力”,而是通过复制少数类样本到某个倍数来增加少数类样本数量,同时不减少多数类样本数。比如,数据集有 1000 个样本,其中 980 属于多数类,20 属于少数类。现在将这 20 个少数类样本各复制 20 次进行过采样,过采样后少数类样本总数将达到 400。

优点:

  • 与欠采样不同,这种方法不会导致信息丢失。

缺点:

  • 由于重复少数类事件,容易导致过拟合。

在考虑采用欠采样或过采样时,可参考以下因素:

  • 当数据量很大时,考虑欠采样
  • 当数据量不大时,考虑过采样
  • 考虑采用随机与非随机(如分层)采样方案
  • 尝试不同的类别比例(例如,二分类并不一定要追求 1:1,可尝试其他比例)

如果想在 Python 中实现欠采样与过采样,可以查看 scikit-learn-contrib。

接下来学习处理失衡数据的另一种方法。

Try generating synthetic samples:

一种简单的方式是:从少数类样本中随机抽取各特征,来创建合成样本。

也有系统化的算法可用于生成合成样本。其中最常用的是 SMOTE(合成少数类过采样技术)。它提出于 2002 年,您可以查看相应论文。下图信息图可帮助理解合成样本的直观含义:

synthetic samples

来源

SMOTE 是一种过采样方法,它通过创建“合成”样本来替代简单的重复。对每个少数类样本,在其与任意/全部 k 个少数类近邻之间的连线上生成合成样本。根据所需的过采样量,从 k 个近邻中随机选择若干近邻。

SMOTE 的核心在于对少数类的构造。直觉很简单:您已经看到,过采样会导致过拟合,因为重复样本会让决策边界收紧。如果能生成相似而非重复的样本,会怎样?原始 SMOTE 论文(见上文链接)表明,对于机器学习算法,这些新构造的样本并非精确副本,从而可以“软化”决策边界,帮助算法更准确地逼近假设。

不过,SMOTE 也有优劣:

优点:

  • 通过生成合成样本,缓解了随机过采样导致的过拟合。
  • 不丢失信息。
  • 实现与解释相对简单。

缺点:

  • 在生成合成样本时,SMOTE 未考虑近邻可能来自其他类别。这会加剧类别重叠并引入额外噪声。
  • 对高维数据不太实用。

SMOTE 还有一些变体,如 safe-level SMOTE、border-line SMOTE、OSSLDDD-SMOTE 等。若要使用 SMOTE 及其变体,可参考前文提到的 scikit-learn-contrib 模块。若想深入了解 SMOTE,可阅读这篇与这篇论文。

下面进入本教程的最后一种思路。

Trying out different perspectives:

有一些专门处理失衡数据集的研究领域,发展出了各自的算法、度量与术语。

在处理失衡数据时,创造力与创新思维往往能带来新的视角。以下方法可作为起点:

代价敏感学习(Cost-Sensitive Learning):通常,您会使用正则化(如果想进一步了解正则化,可参阅这篇 DataCamp 文章)来惩罚在广义线性模型(GLM)中常出现的大系数。不同模型的应用会有所差异,这里暂以 GLM 为例。如果您能设计一种机制,让分类器在每次误分类时都受到惩罚,那么分类器就能以更细致的方式去学习假设。

以下方法值得考虑:

  • 正确地使用 K 折交叉验证
  • 对不同重采样的数据集进行集成
  • 以不同的比例进行重采样
  • 对占优类别进行聚类

Wrap up!

至此,您已经了解了什么是失衡数据,以及它在设计与开发机器学习模型时会引发的问题。您也看到了为什么必须重视失衡数据。随后,我们学习了多种有效处理失衡数据集的方法。处理失衡数据是一个活跃的研究领域,它也为您提供了开拓新研究问题的方向。

一下子涉及这么多重要概念!非常棒!

本教程就到这里。

如果您想更深入地学习失衡数据主题,以下是一些论文链接:

参考资料:

如果您想进一步学习数据可视化,欢迎学习 DataCamp 由 Bokeh 开发者之一 Bryan Van de Ven 授课的 “Interactive Data Visualization with Bokeh” 课程。

主题