如何用 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爬虫之抓取糗事百科代码分享
Nov 06 Python
Python新手们容易犯的几个错误总结
Apr 01 Python
python构建自定义回调函数详解
Jun 20 Python
python与C互相调用的方法详解
Jul 14 Python
Python3利用Dlib19.7实现摄像头人脸识别的方法
May 11 Python
python调用外部程序的实操步骤
Mar 04 Python
python可视化实现KNN算法
Oct 16 Python
Python装饰器使用你可能不知道的几种姿势
Oct 25 Python
python实现随机加减法生成器
Feb 24 Python
python数据预处理 :数据共线性处理详解
Feb 24 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
Sep 04 Python
Selenium执行完毕未关闭chromedriver/geckodriver进程的解决办法(java版+python版)
Dec 07 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
用PHP产生动态的影像图
2006/10/09 PHP
PHP记录搜索引擎蜘蛛访问网站足迹的方法
2015/04/15 PHP
Yii2数据库操作常用方法小结
2017/05/04 PHP
关于laravel框架中的常用目录路径函数
2019/10/23 PHP
jQuery getJSON 处理json数据的代码
2010/07/26 Javascript
extjs中grid中嵌入动态combobox的应用
2011/01/01 Javascript
setTimeout和setInterval的区别你真的了解吗?
2011/03/31 Javascript
Jquery实现仿新浪微博获取文本框能输入的字数代码
2013/02/22 Javascript
js中关于一个分号的崩溃示例
2013/11/11 Javascript
javascript中解析四则运算表达式的算法和示例
2014/08/11 Javascript
javascript转换日期字符串为Date日期对象的方法
2015/02/13 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
2016/05/28 Javascript
简单实现轮播图效果的实例
2016/07/15 Javascript
JQuery 设置checkbox值二次无效的解决方法
2016/07/22 Javascript
浅谈jQuery中ajaxPrefilter的应用
2016/08/01 Javascript
js 自带的 map() 方法全面了解
2016/08/16 Javascript
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
python 多线程应用介绍
2012/12/19 Python
浅谈Python数据类型之间的转换
2016/06/08 Python
pandas 透视表中文字段排序方法
2018/11/16 Python
Python爬虫实现验证码登录代码实例
2019/05/10 Python
python调用Matplotlib绘制分布点图
2019/10/18 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
python去除删除数据中\u0000\u0001等unicode字符串的代码
2020/03/06 Python
TensorFlow keras卷积神经网络 添加L2正则化方式
2020/05/22 Python
实例教程 纯CSS3打造非常炫的加载动画效果
2014/11/05 HTML / CSS
前后端结合实现amazeUI分页效果
2020/08/21 HTML / CSS
BONIA官方网站:国际奢侈品牌和皮革专家
2016/11/27 全球购物
美国餐厅用品和厨房设备批发网站:KaTom Restaurant Supply
2018/01/27 全球购物
一套C++笔试题面试题
2012/06/06 面试题
品学兼优的大学生自我评价
2013/09/20 职场文书
反四风对照检查材料思想汇报
2014/09/16 职场文书
2014年护理工作总结范文
2014/11/14 职场文书
电影圆明园观后感
2015/06/03 职场文书
浅谈Python从全局与局部变量到装饰器的相关知识
2021/06/21 Python
教你如何用Python实现人脸识别(含源代码)
2021/06/23 Python