Index

1、到底什么是不平衡数据

2、处理不平衡数据的理论方法

3、Python里有什么包可以处理不平衡样本

4、Python中具体如何处理失衡样本

印象中很久之前有位朋友说要我写一篇如何处理不平衡数据的文章,整理相关的理论与实践知识(可惜本人太懒了,现在才开始写),于是乎有了今天的文章。失衡样本在我们真实世界中是十分常见的,那么我们在机器学习(ML)中使用这些失衡样本数据会出现什么问题呢?如何处理这些失衡样本呢?以下的内容希望对你有所帮助!

到底什么是不平衡数据

失衡数据发生在分类应用场景中,在分类问题中,类别之间的分布不均匀就是失衡的根本,假设有个二分类问题,target为y,那么y的取值范围为0和1,当其中一方(比如y=1)的占比远小于另一方(y=0)的时候,就是失衡样本了。

那么到底是需要差异多少,才算是失衡呢,根本Google Developer的说法,我们一般可以把失衡分为3个程度:

    轻度:20-40%

    中度:1-20%

    极度:<1%

一般来说,失衡样本在我们构建模型的时候看不出什么问题,而且往往我们还可以得到很高的accuracy,为什么呢?假设我们有一个极度失衡的样本,y=1的占比为1%,那么,我们训练的模型,会偏向于把测试集预测为0,这样子模型整体的预测准确性就会有一个很好看的数字,如果我们只是关注这个指标的话,可能就会被骗了。

 处理不平衡数据的理论方法

在我们开始用Python处理失衡样本之前,我们先来了解一波关于处理失衡样本的一些理论知识,前辈们关于这类问题的解决方案,主要包括以下:

    从数据角度:通过应用一些欠采样or过采样技术来处理失衡样本。欠采样就是对多数类进行抽样,保留少数类的全量,使得两类的数量相当,过采样就是对少数类进行多次重复采样,保留多数类的全量,使得两类的数量相当。但是,这类做法也有弊端,欠采样会导致我们丢失一部分的信息,可能包含了一些重要的信息,过采样则会导致分类器容易过拟合。当然,也可以是两种技术的相互结合。

    从算法角度:算法角度的解决方案就是可以通过对每类的训练实例给予一定权值的调整。比如像在SVM这样子的有参分类器中,可以应用grid search(网格搜索)以及交叉验证(cross validation)来优化C以及gamma值。而对于决策树这类的非参数模型,可以通过调整树叶节点上的概率估计从而实现效果优化。

此外,也有研究员从数据以及算法的结合角度来看待这类问题,提出了两者结合体的AdaOUBoost(adaptive over-sampling and undersampling boost)算法,这个算法的新颖之处在于自适应地对少数类样本进行过采样,然后对多数类样本进行欠采样,以形成不同的分类器,并根据其准确度将这些子分类器组合在一起从而形成强大的分类器,更多的请参考:

    AdaOUBoost:https://dl.acm.org/doi/10.1145/1743384.1743408

Python里有什么包可以处理不平衡样本

这里介绍一个很不错的包,叫 imbalanced-learn,大家可以在电脑上安装一下使用。

    官方文档:https://imbalanced-learn.readthedocs.io/en/stable/index.html

pip install -U imbalanced-learn

使用上面的包,我们就可以实现样本的欠采样、过采样,并且可以利用pipeline的方式来实现两者的结合,十分方便,我们下一节来简单使用一下吧!

 Python中具体如何处理失衡样本

为了更好滴理解,我们引入一个数据集,来自于UCI机器学习存储库的营销活动数据集。(数据集大家可以自己去官网下载:https://archive.ics.uci.edu/ml/machine-learning-databases/00222/  下载bank-additional.zip 或者到公众号后台回复关键字“bank”来获取吧。)

我们在完成imblearn库的安装之后,就可以开始简单的操作了(其余更加复杂的操作可以直接看官方文档),以下我会从4方面来演示如何用Python处理失衡样本,分别是:

1、随机欠采样的实现

 2、使用SMOTE进行过采样

3、欠采样和过采样的结合(使用pipeline)

4、如何获取最佳的采样率?

 那我们开始吧!

    # 导入相关的库(主要就是imblearn库)

    from collections import Counter

    from sklearn.model_selection import train_test_split

    from sklearn.model_selection import cross_val_score

    import pandas as pd

    import numpy as np

    import warnings

    warnings.simplefilter(action='ignore', category=FutureWarning)

    from sklearn.svm import SVC

    from sklearn.metrics import classification_report, roc_auc_score

    from numpy import mean

    # 导入数据

    df = pd.read_csv(r'./data/bank-additional/bank-additional-full.csv', ';') # '';'' 为分隔符

    df.head()

[点击并拖拽以移动]

数据集是葡萄牙银行的某次营销活动的数据,其营销目标就是让客户订阅他们的产品,然后他们通过与客户的电话沟通以及其他渠道获取到的客户信息,组成了这个数据集。

关于字段释义,可以看下面的截图:

[点击并拖拽以移动]

我们可以大致看看数据集是不是失衡样本:

    df['y'].value_counts()/len(df)

    #no     0.887346

    #yes    0.112654

    #Name: y, dtype: float64

可以看出少数类的占比为11.2%,属于中度失衡样本。

    # 只保留数值型变量(简单操作)

    df = df.loc[:,

    ['age', 'duration', 'campaign', 'pdays',

           'previous', 'emp.var.rate', 'cons.price.idx',

           'cons.conf.idx', 'euribor3m', 'nr.employed','y']]

    # target由 yes/no 转为 0/1

    df['y'] = df['y'].apply(lambda x: 1 if x=='yes' else 0)

    df['y'].value_counts()

    #0    36548

    #1     4640

    #Name: y, dtype: int64

 1、随机欠采样的实现

欠采样在imblearn库中也是有方法可以用的,那就是 under_sampling.RandomUnderSampler,我们可以使用把方法引入,然后调用它。可见,原先0的样本有21942,欠采样之后就变成了与1一样的数量了(即2770),实现了50%/50%的类别分布。

    # 1、随机欠采样的实现

    # 导入相关的方法

    from imblearn.under_sampling import RandomUnderSampler

    # 划分因变量和自变量

    X = df.iloc[:,:-1]

    y = df.iloc[:,-1]

    # 划分训练集和测试集

    X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.40)

    # 统计当前的类别占比情况

    print("Before undersampling: ", Counter(y_train))

    # 调用方法进行欠采样

    undersample = RandomUnderSampler(sampling_strategy='majority')

    # 获得欠采样后的样本

    X_train_under, y_train_under = undersample.fit_resample(X_train, y_train)

    # 统计欠采样后的类别占比情况

    print("After undersampling: ", Counter(y_train_under))

    # 调用支持向量机算法 SVC

    model=SVC()

    clf = model.fit(X_train, y_train)

    pred = clf.predict(X_test)

    print("ROC AUC score for original data: ", roc_auc_score(y_test, pred))

    clf_under = model.fit(X_train_under, y_train_under)

    pred_under = clf_under.predict(X_test)

    print("ROC AUC score for undersampled data: ", roc_auc_score(y_test, pred_under))

    # Output:

    #Before undersampling:  Counter({0: 21942, 1: 2770})

    #After undersampling:  Counter({0: 2770, 1: 2770})

    #ROC AUC score for original data:  0.603521152028

    #ROC AUC score for undersampled data:  0.829234085179

 2、使用SMOTE进行过采样

过采样技术中,SMOTE被认为是最为流行的数据采样算法之一,它是基于随机过采样算法的一种改良版本,由于随机过采样只是采取了简单复制样本的策略来进行样本的扩增,这样子会导致一个比较直接的问题就是过拟合。因此,SMOTE的基本思想就是对少数类样本进行分析并合成新样本添加到数据集中。

    算法流程如下:

    (1)对于少数类中每一个样本x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻。

    (2)根据样本不平衡比例设置一个采样比例以确定采样倍率N,对于每一个少数类样本x,从其k近邻中随机选择若干个样本,假设选择的近邻为xn。

    (3)对于每一个随机选出的近邻xn,分别与原样本按照如下的公式构建新的样本。

[点击并拖拽以移动]

    # 2、使用SMOTE进行过采样

    # 导入相关的方法

    from imblearn.over_sampling import SMOTE

    # 划分因变量和自变量

    X = df.iloc[:,:-1]

    y = df.iloc[:,-1]

    # 划分训练集和测试集

    X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.40)

    # 统计当前的类别占比情况

    print("Before oversampling: ", Counter(y_train))

    # 调用方法进行过采样

    SMOTE = SMOTE()

    # 获得过采样后的样本

    X_train_SMOTE, y_train_SMOTE = SMOTE.fit_resample(X_train, y_train)

    # 统计过采样后的类别占比情况

    print("After oversampling: ",Counter(y_train_SMOTE))

    # 调用支持向量机算法 SVC

    model=SVC()

    clf = model.fit(X_train, y_train)

    pred = clf.predict(X_test)

    print("ROC AUC score for original data: ", roc_auc_score(y_test, pred))

    clf_SMOTE= model.fit(X_train_SMOTE, y_train_SMOTE)

    pred_SMOTE = clf_SMOTE.predict(X_test)

    print("ROC AUC score for oversampling data: ", roc_auc_score(y_test, pred_SMOTE))

    # Output:

    #Before oversampling:  Counter({0: 21980, 1: 2732})

    #After oversampling:  Counter({0: 21980, 1: 21980})

    #ROC AUC score for original data:  0.602555700614

    #ROC AUC score for oversampling data:  0.844305732561

 3、欠采样和过采样的结合(使用pipeline)

那如果我们需要同时使用过采样以及欠采样,那该怎么做呢?其实很简单,就是使用 pipeline来实现。

    #  3、欠采样和过采样的结合(使用pipeline)

    # 导入相关的方法

    from imblearn.over_sampling import SMOTE

    from imblearn.under_sampling import RandomUnderSampler

    from imblearn.pipeline import Pipeline

    # 划分因变量和自变量

    X = df.iloc[:,:-1]

    y = df.iloc[:,-1]

    #  定义管道

    model = SVC()

    over = SMOTE(sampling_strategy=0.4)

    under = RandomUnderSampler(sampling_strategy=0.5)

    steps = [('o', over), ('u', under), ('model', model)]

    pipeline = Pipeline(steps=steps)

    # 评估效果

    scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=5, n_jobs=-1)

    score = mean(scores)

    print('ROC AUC score for the combined sampling method: %.3f' % score)

    # Output:

    #ROC AUC score for the combined sampling method: 0.937

 4、如何获取最佳的采样率?

在上面的栗子中,我们都是默认经过采样变成50:50,但是这样子的采样比例并非最优选择,因此我们引入一个叫 最佳采样率的概念,然后我们通过设置采样的比例,采样网格搜索的方法去找到这个最优点。

    # 4、如何获取最佳的采样率?

    # 导入相关的方法

    from imblearn.over_sampling import SMOTE

    from imblearn.under_sampling import RandomUnderSampler

    from imblearn.pipeline import Pipeline

    # 划分因变量和自变量

    X = df.iloc[:,:-1]

    y = df.iloc[:,-1]

    # values to evaluate

    over_values = [0.3,0.4,0.5]

    under_values = [0.7,0.6,0.5]

    for o in over_values:

      for u in under_values:

        # define pipeline

        model = SVC()

        over = SMOTE(sampling_strategy=o)

        under = RandomUnderSampler(sampling_strategy=u)

        steps = [('over', over), ('under', under), ('model', model)]

        pipeline = Pipeline(steps=steps)

        # evaluate pipeline

        scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=5, n_jobs=-1)

        score = mean(scores)

        print('SMOTE oversampling rate:%.1f, Random undersampling rate:%.1f , Mean ROC AUC: %.3f' % (o, u, score))

        

    # Output:    

    #SMOTE oversampling rate:0.3, Random undersampling rate:0.7 , Mean ROC AUC: 0.938

    #SMOTE oversampling rate:0.3, Random undersampling rate:0.6 , Mean ROC AUC: 0.936

    #SMOTE oversampling rate:0.3, Random undersampling rate:0.5 , Mean ROC AUC: 0.937

    #SMOTE oversampling rate:0.4, Random undersampling rate:0.7 , Mean ROC AUC: 0.938

    #SMOTE oversampling rate:0.4, Random undersampling rate:0.6 , Mean ROC AUC: 0.937

    #SMOTE oversampling rate:0.4, Random undersampling rate:0.5 , Mean ROC AUC: 0.938

    #SMOTE oversampling rate:0.5, Random undersampling rate:0.7 , Mean ROC AUC: 0.939

    #SMOTE oversampling rate:0.5, Random undersampling rate:0.6 , Mean ROC AUC: 0.938

    #SMOTE oversampling rate:0.5, Random undersampling rate:0.5 , Mean ROC AUC: 0.938

从结果日志来看,最优的采样率就是过采样0.5,欠采样0.7。

最后,想和大家说的是没有绝对的套路,只有合适的套路,无论是欠采样还是过采样,只有合适才最重要。还有,欠采样的确会比过采样“省钱”哈(从训练时间上很直观可以感受到)。

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

想要获取更多Python学习资料可以加QQ:2955637827私聊或加Q群630390733大家一起来学习讨论吧!

如何在Python中处理不平衡数据的更多相关文章

  1. 如何在Python中从零开始实现随机森林

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 决策树可能会受到高度变异的影响,使得结果对所使用的特定测试数据而言变得脆弱. 根据您的测试数据样本构建多个模型(称为套袋)可以减少这种差异,但是 ...

  2. 如何在Python中使用Linux epoll

    如何在Python中使用Linux epoll 内容 介绍 阻塞套接字编程示例 异步套接字和Linux epoll的好处 epoll的异步套接字编程示例 性能考量 源代码 介绍 从2.6版开始,Pyt ...

  3. 面试官问我:如何在 Python 中解析和修改 XML

    摘要:我们经常需要解析用不同语言编写的数据.Python提供了许多库来解析或拆分用其他语言编写的数据.在此 Python XML 解析器教程中,您将学习如何使用 Python 解析 XML. 本文分享 ...

  4. 如何在Python中加速信号处理

    如何在Python中加速信号处理 This post is the eighth installment of the series of articles on the RAPIDS ecosyst ...

  5. python中json格式数据输出实现方式

    python中json格式数据输出实现方式 主要使用json模块,直接导入import json即可. 小例子如下: #coding=UTF-8 import json info={} info[&q ...

  6. 分析Python中解析构建数据知识

    分析Python中解析构建数据知识 Python 可以通过各种库去解析我们常见的数据.其中 csv 文件以纯文本形式存储表格数据,以某字符作为分隔值,通常为逗号:xml 可拓展标记语言,很像超文本标记 ...

  7. 如何在Python中快速画图——使用Jupyter notebook的魔法函数(magic function)matplotlib inline

    如何在Python中快速画图--使用Jupyter notebook的魔法函数(magic function)matplotlib inline 先展示一段相关的代码: #we test the ac ...

  8. Electron-vue实战(三)— 如何在Vuex中管理Mock数据

    Electron-vue实战(三)— 如何在Vuex中管理Mock数据 作者:狐狸家的鱼 本文链接:Vuex管理Mock数据 GitHub:sueRimn 在vuex中管理mock数据 关于vuex的 ...

  9. 如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python 注释

    如何在Python 中使用UTF-8 编码 && Python 使用 注释,Python ,UTF-8 编码 , Python  注释 PIP $ pip install beauti ...

随机推荐

  1. DIV设置滚动条在最底端

    网站聊天样式,无论添加什么内容div的滚动条都显示在最底端 将div添加滚动条,给div一定的高度 <div id='up' style='height:100px; width:400px;o ...

  2. 宝塔Linux面板安装

    宝塔linux6.0版本是基于centos7开发的,务必使用centos7.x 系统 提示:Centos官方已宣布在2020年停止对Centos6的维护更新,各大软件开发商也逐渐停止对Centos6的 ...

  3. ubuntu解决安装速度问题

    速度慢得原因:linux系统很多的软件源链接都是在国外服务器上,由于国内防火墙影响导致下载速度极慢,甚至超时. 解决办法一:购买梯子 这样你就可以快速的下载国外服务器的软件包了,但是你得有个可靠得梯子 ...

  4. Linux 学习笔记03丨Linux文件系统、文件基本属性、目录处理及文件查看

    Chapter 2. 文件系统 2.1 Linux 系统目录结构 命令窗口下输入命令: $ ls /,能够看到根目录下的全部目录及文件 树状目录结构为: 最顶级的目录: / :根目录 / 是根目录,~ ...

  5. 【线程池】toString

    java.util.concurrent.RejectedExecutionException: Task com.personal.practice.jvm.Jstacktest$1@7d605a5 ...

  6. 20190626_二次开发BarTender打印机_C#代码_一边读取TID_一边打印_打印机POSTEK

    demo代码如下: private void btnPrint_Click(object sender, EventArgs e) { if (this.btnPrint.Text == " ...

  7. 排序--ShellSort 希尔排序

    希尔排序 no 实现 希尔排序其实就是插入排序.只不过希尔排序在比较的元素的间隔不是1. 我们知道插入排序 都是 一个一个和之前的元素比较.发现比之前元素小就交换位置.但是希尔排序可能是和前第n个元素 ...

  8. Django结合Websocket进行WebSSH的实现

    什么是webssh? 泛指一种技术可以在网页上实现一个 终端.从而无需 之类的模拟终端工具进行 连接,将 这一比较低层的操作也从 架构扭成了 架构 这样的架构常用在运维制作开发一些堡垒机等系统中,或是 ...

  9. PyQt(Python+Qt)学习随笔:QListWidgetItem的构造方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListWidgetItem对象专门用于作为QListWidget对象的一个项. QListWid ...

  10. PyQt(Python+Qt)学习随笔:QStandardItemModel指定行和列创建模型中的项以及索引

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 QStandardItemModel有两种构造方法: QStandardItemModel ...