前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >特征锦囊:如何在Python中处理不平衡数据

特征锦囊:如何在Python中处理不平衡数据

作者头像
Sam Gor
发布于 2020-11-19 07:19:26
发布于 2020-11-19 07:19:26
2.5K00
代码可运行
举报
文章被收录于专栏:SAMshareSAMshare
运行总次数:0
代码可运行

今日锦囊

特征锦囊:如何在Python中处理不平衡数据

? 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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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、如何获取最佳的采样率?

??? 那我们开始吧!
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 导入相关的库(主要就是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()

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

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
df['y'].value_counts()/len(df)

#no     0.887346
#yes    0.112654
#Name: y, dtype: float64

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 只保留数值型变量(简单操作)
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%的类别分布。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 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,分别与原样本按照如下的公式构建新的样本。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 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来实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#  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,但是这样子的采样比例并非最优选择,因此我们引入一个叫 最佳采样率的概念,然后我们通过设置采样的比例,采样网格搜索的方法去找到这个最优点。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 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。

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

References

[1] SMOTE算法 https://www.jianshu.com/p/13fc0f7f5565

[2] How to deal with imbalanced data in Python

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SAMshare 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
手写dubbo 5-服务治理(redis番外篇)
博客中代码地址:https://github.com/farliu/farpc.git
并发笔记
2019/07/19
6020
手写dubbo 5-服务治理(redis番外篇)
基于Redis实现分布式消息队列(二)
1、访问Redis的工具类 public class RedisManager {
后端技术探索
2018/08/09
6520
【Jedis配置】springSSM + Jedis连接池配置
当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何方法定义),表示该类可以序列化.序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列,可以。 把该字节序列保存起来(例如:保存在一个文件里),以后可以随时将该字节序列恢复为原来的对象。甚至可以将该字节序列放到其他计算机上或者通过网络传输到其他计算机上恢复,只要该计 算机平台存在相应的类就可以正常恢复为原来的对象。 实现:要序列化一个对象,先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,再调用writeObject()方法即可序列化一个对象;反序列化也类似。 注意:使用对象流写入到文件是不仅要保证该对象是序列化的,而且该对象的成员对象也必须是序列化的
用户5640963
2019/07/25
2.9K0
jedispool使用自动归还jedis解决方案「建议收藏」
在使用jedispool的时候遇到一个尴尬的问题。实例必须要手动归还。即jedis高版本的jedis.close()来归还。 由于我们系统是用grpc做通信机制,所以不存在通过spring 管理实例的生命周期来控制,经研究决定也决定不采用Redisson. 那接下来只有用比较扎实的办法了。 封装一层实现归还。附上代码。。。有更强大的方法欢迎指导。 “` /* Title: Redis操作接口 * Description: * * @author wenquan * @date 2017年1月4日 */ public class RedisUtil { private static JedisPool pool = null;
全栈程序员站长
2022/10/03
9360
redis【redis入门到精通】
Redisredis 是完全开源免费的,是一个高性能的key-value数据库,目前市面上主流的数据库 Redis、Memcache、Tair(淘宝自研发)
高大北
2022/06/27
5940
redis【redis入门到精通】
使用JedisPool资源池操作Redis,并进行性能优化
JedisPool保证资源在一个可控范围内,并且提供了线程安全,但是一个合理的GenericObjectPoolConfig配置能为应用使用Redis保驾护航,下面将对它的一些重要参数进行说明和建议:
小勇DW3
2019/06/11
1.5K0
RedisPool操作Redis,工具类实例
redis.properties 配置文件内容 redis.pool.maxActive=100 redis.pool.maxIdle=20 redis.pool.maxWait=3000 redis.pool.testOnBorrow=false redis.pool.testOnReturn=false redis.ip=127.0.0.1 redis.port=6379 redis.port1=6380 redis.password=**** package com.szreach.rcrp
生活创客
2018/01/30
1.9K0
Spring-Data-Redis 2.X以上版本使用心得和一些坑
最近在修改之前旧项目的时候,将spring-data-redis的版本升级到了2.X以上,查看了官方的文档之后,发现新版本有一些新特性和新的使用方法,这里记录整理一下,并附上自己在使用的时候遇到的一点坑。 spring-data-redis最新版官方文档
星如月勿忘初心
2020/08/02
4.1K1
redis分布式锁加锁删除
下面的分布式锁分别是利用JedisPool 和Redisson 实现的,可以选择行使用。其中方法的命名匹配的为一类,希望可以帮助大家!
gfu
2019/08/28
1.8K0
项目-无侵入代码方式使用Redis实现缓存功能
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
洋仔聊编程
2019/10/25
1.2K0
redis的sentinel主从切换(failover)与Jedis线程池自动重连
本文介绍如何通过sentinel监控redis主从集群,并通过jedis自动切换ip和端口。 1、配置redis主从实例 10.93.21.21:6379 10.93.21.21:6389 10.93.21.21:6399 主从同步关系 master:10.93.21.21:6379 slave:10.93.21.21:6389,10.93.21.21:6399 master配置如下: # 实例ip和端口 bind 10.93.21.21 port 6379 # pid文件 pidfile redis_63
用户1225216
2018/03/05
2.3K0
ssm整合Redis
这次谈谈Redis,关于Redis应该很多朋友就算没有用过也听过,算是这几年最流行的NoSql之一了。 
似水的流年
2018/01/14
2.7K0
nodejs的redis工具类 原
做一个工具时,起初用到redis,后来发现有更好的解决方案,遂放弃redis,但辛辛苦苦写的code不舍得删,这里记录下
尚浩宇
2018/08/17
8950
jedispool是什么_redis工具类
项目中需要用到缓存减少数据库压力,选择redis作为工具,构建一个jedis池达到实际效果 1 1.JedisPoolCacheUtils<!– https://mvnrepository.com/artifact/redis.clients/jedis 引入pom –> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
全栈程序员站长
2022/10/04
4520
springboot 整合redis 操作
六月的雨在Tencent
2024/03/28
1580
springboot 整合redis 操作
FunTester框架Redis压测预备
在超万字回顾FunTester的前世今生一文中我分享了FunTester测试框架一个优点:针对所有Java可实现的接口都能进行功能封装进而进行性能测试。
FunTester
2021/09/14
2690
Shiro+Redis实现tomcat集群session共享
  当我们使用了nginx做项目集群以后,就会出现一个很严重的问题亟待解决,那就是:tomcat集群之间如何实现session共享的问题,如果这个问题不解决,就会出现登陆过后再次请求资源依旧需要登陆的问题。这篇文章我们就解决这个问题。
阿豪聊干货
2018/08/09
8820
Redis实战:Redis在Java中的基本使用
Jedis 是 Java 语言开发的 Redis 客户端工具包,用于 Java 语言与 Redis 数据进行交互。
栗筝i
2023/10/16
1.7K0
Redis实战:Redis在Java中的基本使用
spring boot使用Jedis整合Redis实现缓存(AOP)
使用redis做缓存的话,需要有redis服务,可以将服务部署在远程服务器上,也可以部署到本机上。
洋仔聊编程
2019/01/15
1.9K0
Python-WXPY实现微信监控报警
概述:   本文主要分享一下博主在学习wxpy 的过程中开发的一个小程序。博主在最近有一个监控报警的需求需要完成,然后刚好在学习wxpy 这个东西,因此很巧妙的将工作和学习联系在一起。   博文中主要
九灵
2018/03/09
5.3K0
Python-WXPY实现微信监控报警
推荐阅读
相关推荐
手写dubbo 5-服务治理(redis番外篇)
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 今日锦囊
    • 特征锦囊:如何在Python中处理不平衡数据
      • ? Index
      • ? 到底什么是不平衡数据
      • ? 处理不平衡数据的理论方法
      • ? Python里有什么包可以处理不平衡样本
      • ? Python中具体如何处理失衡样本
      • References
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档