如何用 Python 处理不平衡数据集


Posted in Python onJanuary 04, 2021

1. 什么是数据不平衡

所谓的数据不平衡(imbalanced data)是指数据集中各个类别的数量分布不均衡;不平衡数据在现实任务中十分的常见。如

  • 信用卡欺诈数据:99%都是正常的数据, 1%是欺诈数据
  • 贷款逾期数据

不平衡数据一般是由于数据产生的原因导致的,类别少的样本通常是发生的频率低,需要很长的周期进行采集。

在机器学习任务(如分类问题)中,不平衡数据会导致训练的模型预测的结果会偏向于样本数量多的类别,这个时候除了要选择合适的评估指标外,想要提升模型的性能,就要对数据和模型做一些预处理。

处理数据不平衡的主要方法:

  • 欠采样
  • 过采样
  • 综合采样
  • 模型集成

调整类别权重或者样本权重

2. 数据不平衡处理方法

imbalanced-learn库提供了许多不平衡数据处理的方法,本文的例子都以imbalanced-learn库来实现。

pip install -U imbalanced-learn 

https://github.com/scikit-learn-contrib/imbalanced-learn

本文例子的数据来自进行中的比赛山东省第二届数据应用创新创业大赛-日照分赛场-公积金贷款逾期预测

先来看下数据

import pandas as pd
train_data = './data/train.csv'
test_data = './data/test.csv'
train_df = pd.read_csv(train_data)
test_df = pd.read_csv(test_data)

print(train_df.groupby(['label']).size())
# label为是否违约, 1为违约, 0为非违约
#     label
# 0    37243
# 1     2757

如何用 Python 处理不平衡数据集

2.1 欠采样

所谓欠采样,就是将数量多类别(记为majority)的样本进行抽样,使之数量与数量少的类别(minority)的数量相当,以此达到数量的平衡。

如何用 Python 处理不平衡数据集

由于欠采样是丢失了一部分数据,不可避免的使得数量多类别样本的分布发生了变化(方差变大)。好的欠采样策略应该尽可能保持原有数据分布。

欠采样是删除majority的样本,那哪些样本可以删除呢?

  • 一种是overlapping的数据,就是多余的数据
  • 一种是干扰的数据,干扰minority的分布

基于此,有两种思路来欠采样

  • 边界相邻匹配,考虑在近邻空间内删除majority样本,方法如TomekLinks, NearMiss

下面这张图,展示6NN(6个最近邻居)

如何用 Python 处理不平衡数据集

这里重点讲下TomekLinks, TomekLinks方法简单的说:对每一个minority样本找1NN(最近的邻居),如果最近的邻居是majority, 就形成一个tome-links,该方法人为这个majority是干扰的,将它删除。

如何用 Python 处理不平衡数据集

from imblearn.under_sampling import TomekLinks

X_train = train_df.drop(['id', 'type'], axis=1)
y = train_df['label']
tl = TomekLinks()
X_us, y_us = tl.fit_sample(X_train, y)
print(X_us.groupby(['label']).size())
# label
# 0    36069
# 1     2757

从上可知, 有1174个tomek-link被删除,好像删除还不够多,可以测试下是否对分类结果有帮助。需要注意的因为需要计算最近邻,所以样本属性必须数值属性,或者可以转化为数值属性。

  • 聚类

这类方法通过多个聚类,把原始样本划分成多个聚类簇,然后用每个聚类簇的中心来代替这个聚类簇的特性,完成采样的目的。可知,这种采样的样本不是来自原始样本集,而是聚类生成的。

from imblearn.under_sampling import ClusterCentroids 

cc = ClusterCentroids(random_state=42)
X_res, y_res = cc.fit_resample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    2757
# 1    2757

im-balance提供的欠采样的方法如下:

  • Random majority under-sampling with replacement
  • Extraction of majority-minority Tomek links
  • Under-sampling with Cluster Centroids
  • NearMiss-(1 & 2 & 3)
  • Condensed Nearest Neighbour
  • One-Sided Selection
  • Neighboorhood Cleaning Rule
  • Edited Nearest Neighbours
  • Instance Hardness Threshold
  • Repeated Edited Nearest Neighbours
  • AllKNN

2.2 过采样

所谓过采样,就是将数量少的类别(minority)的样本进行copy,使之数量与数量多的类别(majortity)的数量相当,以此达到数量的平衡。由于复制了多份minoruty样本,过采样会改变minority方差。

如何用 Python 处理不平衡数据集

过采样一种简单的方式是随机copy minority的样本;另外一种是根据现有样本生成人造样本。这里介绍人造样本的经典算法SMOTE(Synthetic Minority Over-sampling Technique)。

SMOTE基于minority样本相似的特征空间构造新的人工样本。步骤如下:

  • 选择一个minority样本,计算其KNN邻居
  • 在K个邻居中,随机选择一个近邻
  • 修改某一个特征,偏移一定的大小:偏移的大小为该minority样本与该近邻差距乘以一个小的随机比率(0, 1), 就此生成新样本

如何用 Python 处理不平衡数据集

from imblearn.over_sampling import SMOTE
smote = SMOTE(k_neighbors=5, random_state=42)
X_res, y_res = smote.fit_resample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    37243
# 1    37243

对于SMOTE方法,对每一个minority都会构造新样本。但是并不总是这样的,考虑下面A,B,C三个点。从数据分布来看,C点很可能是一个异常点(Noise),B点是正常分布的点(SAFE),而A点分布在边界位置(DANGER);

直观上,对于C点我们不应该去构造新样本,对B点,构造新样本不会丰富minority类别的分布。只有A点,如果构造新样本能够使得A点从(DANGER)到(SAFE),加强minority类别的分类边界。这个就是Borderline-SMOTE

如何用 Python 处理不平衡数据集

from imblearn.over_sampling import BorderlineSMOTE
bsmote = BorderlineSMOTE(k_neighbors=5, random_state=42)
X_res, y_res = bsmote.fit_resample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    37243
# 1    37243

ADASYN方法从保持样本分布的角度来确定生成数据,生成数据的方式和SMOTE是一样的,不同在于每个minortiy样本生成样本的数量不同。

  • 先确定要生成样本的数量 beta为[0, 1]

如何用 Python 处理不平衡数据集

  • 对每个每个minortiy样本,确定有它生成样本的比例。先找出K最近邻,计算K最近邻中属于majority的样本比例(即分子),Z是归一化因子,保证所有的minortiry的比例和为1,可以认为是所有分子的和。

如何用 Python 处理不平衡数据集

  • 计算每个minortiy生成新样本的数量

如何用 Python 处理不平衡数据集

  • 按照SMOTE方式生成样本
from imblearn.over_sampling import ADASYN 
adasyn = ADASYN(n_neighbors=5, random_state=42)
X_res, y_res = adasyn.fit_resample(X_train, y)
X_res.groupby(['label']).size()

# label
# 0    37243
# 1    36690

im-balance提供的过采样的方法如下(包括SMOTE算法的变种):

  • Random minority over-sampling with replacement
  • SMOTE - Synthetic Minority Over-sampling Technique
  • SMOTENC - SMOTE for Nominal Continuous
  • bSMOTE(1 & 2) - Borderline SMOTE of types 1 and 2
  • SVM SMOTE - Support Vectors SMOTE
  • ADASYN - Adaptive synthetic sampling approach for imbalanced learning
  • KMeans-SMOTE
  • ROSE - Random OverSampling Examples

2.3 综合采样

过采样是针对minority样本,欠采样是针对majority样本;而综合采样是既对minority样本,又对majority样本,同时进行操作的方法。主要有SMOTE+Tomek-links和SMOTE+Edited Nearest Neighbours。

综合采样的方法,是先进行过采样,在进行欠采样。

from imblearn.combine import SMOTETomek

smote_tomek = SMOTETomek(random_state=0)
X_res, y_res = smote_tomek.fit_sample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    36260
# 1    36260

2.4 模型集成

这里的模型集成主要体现在数据上,即用众多平衡的数据集(majortiry的样本进行欠采样加上minority样本)训练多个模型,然后进行集成。imblearn.ensemble提供几种常见的模型集成算法,如BalancedRandomForestClassifier

from imblearn.ensemble import BalancedRandomForestClassifier
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=1000, n_classes=3,
                           n_informative=4, weights=[0.2, 0.3, 0.5],
                           random_state=0)
clf = BalancedRandomForestClassifier(max_depth=2, random_state=0)
clf.fit(X, y)  

print(clf.feature_importances_)  
print(clf.predict([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]))

im-balance提供的模型集成的方法如下

  • Easy Ensemble classifier
  • Balanced Random Forest
  • Balanced Bagging
  • RUSBoost

2.5 调整类别权重或者样本权重

对于很多用梯度下降方法来学习(使得某个损失Loss最小)的机器学习的方法,可以通过调整类别权重或样本权重的方式,来一定程度上平衡不平衡数据。如gbdt模型lightgbm 中 class_weight

import lightgbm as lgb
clf = lgb.LGBMRegressor(num_leaves=31, 
                        min_child_samples= np.random.randint(20,25),
                        max_depth=25,
                        learning_rate=0.1, 
                        class_weight={0:1, 1:10},
                        n_estimators=500, 
                        n_jobs=30)

3. 总结

本文分享了常见的几种处理不平衡数据集的方法,并且提供imbalanced-learn的简单例子。总结如下:

  • 欠采样: 减少majoritry样本
  • 过采样:增加minority样本
  • 综合采样:先过采样,在欠采样
  • 模型集成:制造平衡数据(majoritry样本欠采样+minority样本),多次不同的欠采样,训练不同的模型,然后融合
  • 不管是欠采样和过采样,都一定程度的改变了原始数据的分布,可能造成模型过拟合。需要去尝试哪种方法,符合实际的数据分布。当然不一定有效果,去勇敢尝试吧 just do it!

4. 参考资料

  • Learning from Imbalanced Data
  • Two Modifications of CNN(Tomek links,CNN乍一看还以为卷积神经网络,其实是condensed nearest-neighbor)
  • imbalanced-learn API:https://imbalanced-learn.org/stable/

以上就是如何用 Python 处理不平衡数据集的详细内容,更多关于Python 处理不平衡数据集的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python的类方法和静态方法
Dec 13 Python
安装python时MySQLdb报错的问题描述及解决方法
Mar 20 Python
Django实现分页功能
Jul 02 Python
使用Py2Exe for Python3创建自己的exe程序示例
Oct 31 Python
Pandas读写CSV文件的方法示例
Mar 27 Python
Python内置random模块生成随机数的方法
May 31 Python
Python 的字典(Dict)是如何存储的
Jul 05 Python
python多环境切换及pyenv使用过程详解
Sep 27 Python
Django中密码的加密、验密、解密操作
Dec 19 Python
如何理解Python中的变量
Jun 01 Python
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
Apr 11 Python
python中pd.cut()与pd.qcut()的对比及示例
Jun 16 Python
Python创建简单的神经网络实例讲解
Jan 04 #Python
python实现跨年表白神器--你值得拥有
Jan 04 #Python
Python列表元素删除和remove()方法详解
Jan 04 #Python
python3列表删除大量重复元素remove()方法的问题详解
Jan 04 #Python
关于python中remove的一些坑小结
Jan 04 #Python
python中remove函数的踩坑记录
Jan 04 #Python
python 日志模块logging的使用场景及示例
Jan 04 #Python
You might like
为查询结果建立向后/向前按钮
2006/10/09 PHP
php cookie 作用范围?不要在当前页面使用你的cookie
2009/03/24 PHP
基于PHP对XML的操作详解
2013/06/07 PHP
PHP小技巧之函数重载
2014/06/02 PHP
PHP将回调函数作用到给定数组单元的方法
2014/08/19 PHP
PHP的HTTP客户端Guzzle简单使用方法分析
2019/10/30 PHP
Google Map Api和GOOGLE Search Api整合实现代码
2009/07/18 Javascript
jquery获取特定name所有选中的checkbox,支持IE9标准模式
2013/03/18 Javascript
jQuery表单美化插件jqTransform使用详解
2015/04/12 Javascript
JS实现字符串转日期并比较大小实例分析
2015/12/09 Javascript
JS变量及其作用域
2017/03/29 Javascript
利用C/C++编写node.js原生模块的方法教程
2017/07/07 Javascript
解决html input验证只能输入数字,不能输入其他的问题
2017/07/21 Javascript
vue mixins组件复用的几种方式(小结)
2017/09/06 Javascript
JavaScript实现单击网页任意位置打开新窗口与关闭窗口的方法
2017/09/21 Javascript
AngularJS中重新加载当前路由页面的方法
2018/03/09 Javascript
Node.js文件编码格式的转换的方法
2018/04/27 Javascript
跨域请求两种方法 jsonp和cors的实现
2018/11/11 Javascript
javaScript把其它类型转换为Number类型
2019/10/13 Javascript
JS造成内存泄漏的几种情况实例分析
2020/03/02 Javascript
Vue之封装公用变量以及实现方式
2020/07/31 Javascript
详解JavaScript 高阶函数
2020/09/14 Javascript
python中异常捕获方法详解
2017/03/03 Python
对python mayavi三维绘图的实现详解
2019/01/08 Python
python requests库爬取豆瓣电视剧数据并保存到本地详解
2019/08/10 Python
python GUI框架pyqt5 对图片进行流式布局的方法(瀑布流flowlayout)
2020/03/12 Python
AmazeUI 网格的实现示例
2020/08/13 HTML / CSS
英国著名音像制品和图书游戏购物网站:Zavvi
2016/08/04 全球购物
丝芙兰香港官网:Sephora香港
2018/03/13 全球购物
Farfetch台湾官网:奢侈品牌时尚购物平台
2019/06/17 全球购物
小班重阳节活动方案
2014/02/08 职场文书
给校长的建议书600字
2014/05/15 职场文书
邮政营业员岗位职责
2015/04/14 职场文书
高二化学教学反思
2016/02/22 职场文书
html5移动端禁止长按图片保存的实现
2021/04/20 HTML / CSS
Vscode中SSH插件如何远程连接Linux
2022/05/02 Servers