[转]如何处理机器学习中的不平衡类别

如何处理机器学习中的不平衡类别

如何处理机器学习中的不平衡类别

不平衡类别使得“准确率”失去意义。这是机器学习 (特别是在分类)中一个令人惊讶的常见问题,出现于每个类别的观测样本不成比例的数据集中。

普通的准确率不再能够可靠地度量性能,这使得模型训练变得更加困难。

不平衡类别出现在多个领域,包括:

  • 欺诈检测
  • 垃圾邮件过滤
  • 疾病筛查
  • SaaS 客户流失
  • 广告点击率

在本指南中,我们将探讨 5 种处理不平衡类别的有效方法。

How to Handle Imbalanced Classes in Machine Learning

直观的例子:疾病筛查案例

假如你的客户是一家先进的研究医院,他们要求你基于采集于病人的生物输入来训练一个用于检测一种疾病的模型。

但这里有陷阱... 疾病非常罕见;筛查的病人中只有 8% 的患病率。

现在,在你开始之前,你觉得问题可能会怎样发展呢?想象一下,如果你根本没有去训练一个模型。相反,如果你只写一行代码,总是预测“没有疾病”,那会如何呢?

一个拙劣但准确的解决方案

def disease_screen(patient_data):
    # 忽略 patient_data
    return ‘No Disease.‘

很好,猜猜看?你的“解决方案”应该有 92% 的准确率!

不幸的是,以上准确率具有误导性。

  • 对于未患该病的病人,你的准确率是 100% 。
  • 对于已患该病的病人,你的准确率是 0%。
  • 你的总体准确率非常高,因为大多数患者并没有患该病 (不是因为你的模型训练的好)。

这显然是一个问题,因为设计的许多机器学习算法是为了最大限度的提高整体准确率。本指南的其余部分将说明处理不平衡类别的不同策略。

我们开始之前的重要提示:

首先,请注意,我们不会分离出一个独立的测试集,调整超参数或者实现交叉检验。换句话说,我们不打算遵循最佳做法 (在我们的7 天速成课程中有介绍)。

相反,本教程只专注于解决不平衡类别问题。

此外,并非以下每种技术都会适用于每一个问题。不过通常来说,这些技术中至少有一个能够解决问题。

Balance Scale 数据集

对于本指南,我们将会使用一个叫做 Balance Scale 数据的合成数据集,你可以从这里 UCI 机器学习仓库下载。

这个数据集最初被生成用于模拟心理实验结果,但是对于我们非常有用,因为它的规模便于处理并且包含不平衡类别

导入第三方依赖库并读取数据

import pandas as pd
import numpy as np

# 读取数据集
df = pd.read_csv(‘balance-scale.data‘,
                 names=[‘balance‘, ‘var1‘, ‘var2‘, ‘var3‘, ‘var4‘])

# 显示示例观测样本
df.head()

Balance Scale Dataset

基于两臂的重量和距离,该数据集包含了天平是否平衡的信息。

  • 其中包含 1 个我们标记的目标变量

    balance .
  • 其中包含 4 个我们标记的输入特征
    var1  到
    var4 .

Image Scale Data

目标变量有三个类别。

  • R 表示右边重,,当

    var3*var4>var1*var2
  • L 表示左边重,当
    var3*var4<var1*var2
  • B 表示平衡,当
    var3*var4=var1*var2

每个类别的数量

df[‘balance‘].value_counts()
# R    288
# L    288
# B     49
# Name: balance, dtype: int64

然而,对于本教程, 我们将把本问题转化为 二值分类 问题。

我们将把天平平衡时的每个观测样本标记为 1 (正向类别),否则标记为 0 (负向类别):

转变成二值分类

# 转换为二值分类
df[‘balance‘] = [1 if b==‘B‘ else 0 for b in df.balance]

df[‘balance‘].value_counts()
# 0    576
# 1     49
# Name: balance, dtype: int64
# About 8% were balanced

正如你所看到的,只有大约 8% 的观察样本是平衡的。 因此,如果我们的预测结果总为 0,我们就会得到 92% 的准确率。

不平衡类别的风险

现在我们有一个数据集,我们可以真正地展示不平衡类别的风险。

首先,让我们从 Scikit-Learn 导入逻辑回归算法和准确度度量模块。

导入算法和准确度度量模块

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

接着,我们将会使用默认设置来生成一个简单的模型。

在不平衡数据上训练一个模型

# 分离输入特征 (X) 和目标变量 (y)
y = df.balance
X = df.drop(‘balance‘, axis=1)

# 训练模型
clf_0 = LogisticRegression().fit(X, y)

# 在训练集上预测
pred_y_0 = clf_0.predict(X)

如上所述,许多机器学习算法被设计为在默认情况下最大化总体准确率。

我们可以证实这一点:

# 准确率是怎样的?
print( accuracy_score(pred_y_0, y) )
# 0.9216

因此我们的模型拥有 92% 的总体准确率,但是这是因为它只预测了一个类别吗?

# 我们应该兴奋吗?
print( np.unique( pred_y_0 ) )
# [0]

正如你所看到的,这个模型仅能预测 0,这就意味着它完全忽视了少数类别而偏爱多数类别。

接着,我们将会看到第一个处理不平衡类别的技术:上采样少数类别。

1. 上采样少数类别

上采样是从少数类别中随机复制观测样本以增强其信号的过程。

达到这个目的有几种试探法,但是最常见的方法是使用简单的放回抽样的方式重采样。

首先,我们将从 Scikit-Learn 中导入重采样模块:

重采样模块

from sklearn.utils import resample

接着,我们将会使用一个上采样过的少数类别创建一个新的 DataFrame。 下面是详细步骤:

  1. 首先,我们将每个类别的观测样本分离到不同的 DataFrame 中。
  2. 接着,我们将采用放回抽样的方式对少数类别重采样,让样本的数量与多数类别数量相当。
  3. 最后,我们将上采样后的少数类别 DataFrame 与原始的多数类别 DataFrame 合并。

以下是代码:

上采样少数类别

#  分离多数和少数类别
df_majority = df[df.balance==0]
df_minority = df[df.balance==1]

# 上采样少数类别
df_minority_upsampled = resample(df_minority,
                                 replace=True,     # sample with replacement
                                 n_samples=576,    # to match majority class
                                 random_state=123) # reproducible results

# 合并多数类别同上采样过的少数类别
df_upsampled = pd.concat([df_majority, df_minority_upsampled])

# 显示新的类别数量
df_upsampled.balance.value_counts()
# 1    576
# 0    576
# Name: balance, dtype: int64

正如你所看到的,新生成的 DataFrame 比原来拥有更多的观测样本,现在两个类别的比率为 1:1。

让我们使用逻辑回归训练另一个模型,这次我们在平衡数据集上进行:

在上采样后的数据集上训练模型

# 分离输入特征 (X) 和目标变量 (y)
y = df_upsampled.balance
X = df_upsampled.drop(‘balance‘, axis=1)

# 训练模型
clf_1 = LogisticRegression().fit(X, y)

# 在训练集上预测
pred_y_1 = clf_1.predict(X)

# 我们的模型仍旧预测仅仅一个类别吗?
print( np.unique( pred_y_1 ) )
# [0 1]

# 我们的准确率如何?
print( accuracy_score(y, pred_y_1) )
# 0.513888888889

非常好,现在这个模型不再只是预测一个类别了。虽然准确率急转直下,但现在的性能指标更有意义。

2. 下采样多数类别

下采样包括从多数类别中随机地移除观测样本,以防止它的信息主导学习算法。

其中最常见的试探法是不放回抽样式重采样。

这个过程同上采样极为相似。下面是详细步骤:

  1. 首先,我们将每个类别的观测样本分离到不同的 DataFrame 中。
  2. 接着,我们将采用不放回抽样来重采样多数类别,让样本的数量与少数类别数量相当。
  3. 最后,我们将下采样后的多数类别 DataFrame 与原始的少数类别 DataFrame 合并。

以下为代码:

下采样多数类别

# 分离多数类别和少数类别
df_majority = df[df.balance==0]
df_minority = df[df.balance==1]

# 下采样多数类别
df_majority_downsampled = resample(df_majority,
                                 replace=False,    # sample without replacement
                                 n_samples=49,     # to match minority class
                                 random_state=123) # reproducible results

# Combine minority class with downsampled majority class
df_downsampled = pd.concat([df_majority_downsampled, df_minority])

# Display new class counts
df_downsampled.balance.value_counts()
# 1    49
# 0    49
# Name: balance, dtype: int64

这次,新生成的 DataFrame 比原始数据拥有更少的观察样本,现在两个类别的比率为 1:1。

让我们再一次使用逻辑回归训练一个模型:

在下采样后的数据集上训练模型

# Separate input features (X) and target variable (y)
y = df_downsampled.balance
X = df_downsampled.drop(‘balance‘, axis=1)

# Train model
clf_2 = LogisticRegression().fit(X, y)

# Predict on training set
pred_y_2 = clf_2.predict(X)

# Is our model still predicting just one class?
print( np.unique( pred_y_2 ) )
# [0 1]

# How‘s our accuracy?
print( accuracy_score(y, pred_y_2) )
# 0.581632653061

模型不再仅预测一个类别,并且其准确率似乎有所提高。

我们还希望在一个未见过的测试数据集上验证模型时, 能看到更令人鼓舞的结果。

3. 改变你的性能指标

目前,我们已经看到通过重采样数据集来解决不平衡类别的问题的两种方法。接着,我们将考虑使用其他性能指标来评估模型。

阿尔伯特?爱因斯坦曾经说过,“如果你根据能不能爬树来判断一条鱼的能力,那你一生都会认为它是愚蠢的。”,这句话真正突出了选择正确评估指标的重要性。

对于分类的通用指标,我们推荐使用 ROC 曲线下面积 (AUROC)。

  • 本指南中我们不做详细介绍,但是你可以在这里阅读更多关于它的信息。
  • 直观地说,AUROC 表示从中类别中区别观测样本的可能性。
  • 换句话说,如果你从每个类别中随机选择一个观察样本,它将被正确的“分类”的概率是多大?

我们可以从 Scikit-Learn 中导入这个指标:

ROC 曲线下面积

from sklearn.metrics import roc_auc_score

为了计算 AUROC,你将需要预测类别的概率,而非仅预测类别。你可以使用如下代码获取这些结果
.predict_proba() function like so:

获取类别概率

# Predict class probabilities
prob_y_2 = clf_2.predict_proba(X)

# Keep only the positive class
prob_y_2 = [p[1] for p in prob_y_2]

prob_y_2[:5] # Example
# [0.45419197226479618,
#  0.48205962213283882,
#  0.46862327066392456,
#  0.47868378832689096,
#  0.58143856820159667]

那么在 AUROC 下 这个模型 (在下采样数据集上训练模型) 效果如何?

下采样后数据集上训练的模型的 AUROC
Python

print( roc_auc_score(y, prob_y_2) )
# 0.568096626406

不错... 这和在不平衡数据集上训练的原始模型相比,又如何呢?

不平衡数据集上训练的模型的 AUROC

prob_y_0 = clf_0.predict_proba(X)
prob_y_0 = [p[1] for p in prob_y_0]

print( roc_auc_score(y, prob_y_0) )
# 0.530718537415

记住,我们在不平衡数据集上训练的原始模型拥有 92% 的准确率,它远高于下采样数据集上训练的模型的 58% 准确率。

然而,后者模型的 AUROC 为 57%,它稍高于 AUROC 为 53% 原始模型的 (并非远高于)。

注意: 如果 AUROC 的值为 0.47,这仅仅意味着你需要翻转预测,因为 Scikit-Learn 误解释了正向类别。 AUROC 应该 >= 0.5。

4. 惩罚算法 (代价敏感学习)

接下来的策略是使用惩罚学习算法来增加对少数类别分类错误的代价。

对于这种技术,一个流行的算法是惩罚性-SVM:

支持向量机

from sklearn.svm import SVC

训练时,我们可以使用参数
class_weight=‘balanced‘ 来减少由于少数类别样本比例不足造成的预测错误。

我们也可以包含参数
probability=True ,如果我们想启用 SVM 算法的概率估计。
让我们在原始的不平衡数据集上使用惩罚性的 SVM 训练模型:

SVM 在不平衡数据集上训练惩罚性-SVM

# 分离输入特征 (X) 和目标变量 (y)
y = df.balance
X = df.drop(‘balance‘, axis=1)

# 训练模型
clf_3 = SVC(kernel=‘linear‘,
            class_weight=‘balanced‘, # penalize
            probability=True)

clf_3.fit(X, y)

# 在训练集上预测
pred_y_3 = clf_3.predict(X)

# Is our model still predicting just one class?
print( np.unique( pred_y_3 ) )
# [0 1]

# How‘s our accuracy?
print( accuracy_score(y, pred_y_3) )
# 0.688

# What about AUROC?
prob_y_3 = clf_3.predict_proba(X)
prob_y_3 = [p[1] for p in prob_y_3]
print( roc_auc_score(y, prob_y_3) )
# 0.5305236678

再说,这里我们的目的只是为了说明这种技术。真正决定哪种策略最适合这个问题,你需要在保留测试集上评估模型。

5. 使用基于树的算法

最后一个策略我们将考虑使用基于树的算法。决策树通常在不平衡数据集上表现良好,因为它们的层级结构允许它们从两个类别去学习。

在现代应用机器学习中,树集合(随机森林、梯度提升树等) 几乎总是优于单一决策树,所以我们将跳过单一决策树直接使用树集合模型:

随机森林

from sklearn.ensemble import RandomForestClassifier

现在,让我们在原始的不平衡数据集上使用随机森林训练一个模型。

在不平衡数据集上训练随机森林

# 分离输入特征 (X) 和目标变量 (y)
y = df.balance
X = df.drop(‘balance‘, axis=1)

# 训练模型
clf_4 = RandomForestClassifier()
clf_4.fit(X, y)

# 在训练集上进行预测
pred_y_4 = clf_4.predict(X)

# 我们的模型仍然仅能预测一个类别吗?
print( np.unique( pred_y_4 ) )
# [0 1]

# 我们的准确率如何?
print( accuracy_score(y, pred_y_4) )
# 0.9744

# AUROC 怎么样?
prob_y_4 = clf_4.predict_proba(X)
prob_y_4 = [p[1] for p in prob_y_4]
print( roc_auc_score(y, prob_y_4) )
# 0.999078798186

哇! 97% 的准确率和接近 100% AUROC 是魔法吗?戏法?作弊?是真的吗?

嗯,树集合已经非常受欢迎,因为他们在许多现实世界的问题上表现的非常良好。我们当然全心全意地推荐他们。

然而:

虽然这些结果令人激动,但是模型可能导致过拟合,因此你在做出最终决策之前仍旧需要在未见过的测试集上评估模型。

注意: 由于算法的随机性,你的结果可能略有不同。为了能够复现试验结果,你可以设置一个随机种子。

顺便提一下

有些策略没有写入本教程:

创建合成样本 (数据增强)

创建合成样本与上采样非常相似, 一些人将它们归为一类。例如, SMOTE 算法 是一种从少数类别中重采样的方法,会轻微的引入噪声,来创建”新“样本。

你可以在 imblearn 库 中 找到 SMOTE 的一种实现

注意:我们的读者之一,马可,提出了一个很好的观点:仅使用 SMOTE 而不适当的使用交叉验证所造成的风险。查看评论部分了解更多详情或阅读他的关于本主题的 博客文章 。

组合少数类别

组合少数类别的目标变量可能适用于某些多类别问题。

例如,假如你希望预测信用卡欺诈行为。在你的数据集中,每种欺诈方式可能会分别标注,但你可能并不关心区分他们。你可以将它们组合到单一类别“欺诈”中并把此问题归为二值分类问题。

重构欺诈检测

异常检测, 又称为离群点检测,是为了检测异常点(或离群点)和小概率事件。不是创建一个分类模型,你会有一个正常观测样本的 ”轮廓“。如果一个新观测样本偏离 “正常轮廓” 太远,那么它就会被标注为一个异常点。

总结 & 下一步

在本指南中,我们介绍了 5 种处理不平衡类别的有效方法:

  1. 上采样 少数类别
  2. 下采样 多数类别
  3. 改变你的性能指标
  4. 惩罚算法 (代价敏感学习)
  5. 使用基于树的算法

原文地址:https://www.cnblogs.com/byteHuang/p/9156263.html

时间: 2024-08-07 18:09:26

[转]如何处理机器学习中的不平衡类别的相关文章

从重采样到数据合成:如何处理机器学习中的不平衡分类问题?

转载自[机器之心]http://www.jiqizhixin.com/article/2499本文作者为来自 KPMG 的数据分析顾问 Upasana Mukherjee 如果你研究过一点机器学习和数据科学,你肯定遇到过不平衡的类分布(imbalanced class distribution).这种情况是指:属于某一类别的观测样本的数量显著少于其它类别. 这个问题在异常检测是至关重要的的场景中很明显,例如电力盗窃.银行的欺诈交易.罕见疾病识别等.在这种情况下,利用传统机器学习算法开发出的预测模

如何解决机器学习中数据不平衡问题

作者:无影随想 时间:2016年1月. 出处:http://www.zhaokv.com/2016/01/learning-from-imbalanced-data.html 声明:版权所有,转载请联系作者并注明出处 这几年来,机器学习和数据挖掘非常火热,它们逐渐为世界带来实际价值.与此同时,越来越多的机器学习算法从学术界走向工业界,而在这个过程中会有很多困难.数据不平衡问题虽然不是最难的,但绝对是最重要的问题之一. 一.数据不平衡 在学术研究与教学中,很多算法都有一个基本假设,那就是数据分布是

蜡炬教育:如何处理机器学习中大型数据的加载问题?

原标题:蜡炬教育:如何处理机器学习中大型数据的加载问题? 蜡炬教育老师表示,在处理机器学习算法时,经常会因为数据库太大而导致无法放入内存中,而遇到这样几个问题:当运行数据集算法而导致崩溃时如何解决?当需要处理大容量数据文件时该如何加载?如何方便快捷的解决内存不足的问题? 针对以上问题,蜡炬教育老师给出7个建议: 1.分配更多内存某些ML工具或数据库默认内存配置不合理,可以看看是否可以手动分配. 2.使用较小样本确认是否需要处理所有数据?在对最终数据拟合前,使用随机抽取数据样本这个示例即可. 3.

机器不学习:如何处理数据中的「类别不平衡」?

机器不学习 jqbxx.com -机器学习好网站 机器学习中常常会遇到数据的类别不平衡(class imbalance),也叫数据偏斜(class skew).以常见的二分类问题为例,我们希望预测病人是否得了某种罕见疾病.但在历史数据中,阳性的比例可能很低(如百分之0.1).在这种情况下,学习出好的分类器是很难的,而且在这种情况下得到结论往往也是很具迷惑性的. 以上面提到的场景来说,如果我们的分类器总是预测一个人未患病,即预测为反例,那么我们依然有高达99.9%的预测准确率.然而这种结果是没有意

机器学习中样本不平衡的处理方法

在现实收集的样本中,正负类别不均衡是现实数据中很常见的问题.一个分类器往往 Accuracy 将近90%,但是对少数样本的判别的 Recall 却只有10%左右.这对于我们正确找出少数类样本非常不利. 举例来说:在一波新手推荐的活动中,预测用户是否会注册的背景下,不注册的用户往往是居多的,这个正负比例通常回事1:99甚至更大.一般而言,正负样本比例超过1:3,分类器就已经会倾向于负样本的判断(表现在负样本Recall过高,而正样本 Recall 低,而整体的 Accuracy依然会有很好的表现)

机器学习中的类别不均衡问题

基础概念 类别不均衡是指在分类学习算法中,不同类别样本的比例相差悬殊,它会对算法的学习过程造成重大的干扰.比如在一个二分类的问题上,有1000个样本,其中5个正样本,995个负样本,在这种情况下,算法只需将所有的样本预测为负样本,那么它的精度也可以达到99.5%,虽然结果的精度很高,但它依然没有价值,因为这样的学习算法不能预测出正样本.这里我们可以知道不均衡问题会导致样本较少那一类的高错分率,即较少一类的样本会有较大的比例会被预测成样本数量较多的那一类. 解决方法 1.欠采样,减少数量较多那一类

机器学习中的数据清洗与特征处理综述

背景 随着美团交易规模的逐步增大,积累下来的业务数据和交易数据越来越多,这些数据是美团做为一个团购平台最宝贵的财富.通过对这些数据的分析和挖掘,不仅能给美团业务发展方向提供决策支持,也为业务的迭代指明了方向.目前在美团的团购系统中大量地应用到了机器学习和数据挖掘技术,例如个性化推荐.筛选排序.搜索排序.用户建模等等,为公司创造了巨大的价值.本文主要介绍在美团的推荐与个性化团队实践中的数据清洗与特征挖掘方法.主要内容已经在内部公开课"机器学习InAction系列"讲过,本博客的内容主要是

机器学习中的回归理解

机器学习中的类别均衡问题? 分为类别平衡问题和类别不平衡问题 类别平衡问题:可以采用回归 类别不平衡问题:可以采用在缩放 针对类别的回归问题有 线性回归: 非线性回

机器学习中的线性模型

一.基本形式 给定由d个属性描述的示例x=(x1, x2, ..., xd),则线性模型(linear mdel)的预测函数f(x)是属性的线性组合,用向量形式表示为f(x) = wTx + b. 线性模型蕴涵了机器学习中一些重要的基本思想.通过在线性模型中引入层次结构或高维映射,就可以得到更为强大的非线性模型(nonlinear model).此外,线性模型也具有很好的可解释性(comprehensibility). 针对回归任务.二分类任务.多分类任务,下文总结了几种经典的线性模型. 二.线