教你用Python解决非平衡数据问题(附代码)
本文为你分享数据挖掘中常见的非平衡数据的处理,内容涉及到非平衡数据的解决方案和原理,以及如何使用Python这个强大的工具实现平衡的转换。
后台回复“不平衡”获取数据及代码~
前言
好久没有更新自己写的文章了,相信很多读者都会比较失望,甚至取关了吧,在此向各位网友道个歉。文章未及时更新的主要原因是目前在写Python和R语言相关的书籍,激动的是基于Python的数据分析与挖掘的书已经编写完毕,后期还继续书写R语言相关的内容。希望得到网友的理解,为晚来的新文章再次表示抱歉。
本次分享的主题是关于数据挖掘中常见的非平衡数据的处理,内容涉及到非平衡数据的解决方案和原理,以及如何使用Python这个强大的工具实现平衡的转换。
SMOTE算法的介绍
在实际应用中,读者可能会碰到一种比较头疼的问题,那就是分类问题中类别型的因变量可能存在严重的偏倚,即类别之间的比例严重失调。如欺诈问题中,欺诈类观测在样本集中毕竟占少数;客户流失问题中,非忠实的客户往往也是占很少一部分;在某营销活动的响应问题中,真正参与活动的客户也同样只是少部分。
如果数据存在严重的不平衡,预测得出的结论往往也是有偏的,即分类结果会偏向于较多观测的类。对于这种问题该如何处理呢?最简单粗暴的办法就是构造1:1的数据,要么将多的那一类砍掉一部分(即欠采样),要么将少的那一类进行Bootstrap抽样(即过采样)。但这样做会存在问题,对于第一种方法,砍掉的数据会导致某些隐含信息的丢失;而第二种方法中,有放回的抽样形成的简单复制,又会使模型产生过拟合。
为了解决数据的非平衡问题,2002年Chawla提出了SMOTE算法,即合成少数过采样技术,它是基于随机过采样算法的一种改进方案。该技术是目前处理非平衡数据的常用手段,并受到学术界和工业界的一致认同,接下来简单描述一下该算法的理论思想。
SMOTE算法的基本思想就是对少数类别样本进行分析和模拟,并将人工模拟的新样本添加到数据集中,进而使原始数据中的类别不再严重失衡。该算法的模拟过程采用了KNN技术,模拟生成新样本的步骤如下:
采样最邻近算法,计算出每个少数类样本的K个近邻;
从K个近邻中随机挑选N个样本进行随机线性插值;
构造新的少数类样本;
将新样本与原数据合成,产生新的训练集;
为了使读者理解SMOTE算法实现新样本的模拟过程,可以参考下图和人工新样本的生成过程:
如上图所示,实心圆点代表的样本数量要明显多于五角星代表的样本点,如果使用SMOTE算法模拟增加少类别的样本点,则需要经过如下几个步骤:
利用KNN算法,选择离样本点x1最近的K个同类样本点(不妨最近邻为5);
从最近的K个同类样本点中,随机挑选M个样本点(不妨M为2),M的选择依赖于最终所希望的平衡率;
对于每一个随机选中的样本点,构造新的样本点;新样本点的构造需要使用下方的公式:
其中,xi表示少数类别中的一个样本点(如图中五角星所代表的x1样本);xj表示从K近邻中随机挑选的样本点j;rand(0,1)表示生成0~1之间的随机数。
假设图中样本点x1的观测值为(2,3,10,7),从图中的5个近邻中随机挑选2个样本点,它们的观测值分别为(1,1,5,8)和(2,1,7,6),所以,由此得到的两个新样本点为:
重复步骤1)、2)和3),通过迭代少数类别中的每一个样本xi,最终将原始的少数类别样本量扩大为理想的比例;
通过SMOTE算法实现过采样的技术并不是太难,读者可以根据上面的步骤自定义一个抽样函数。当然,读者也可以借助于imblearn模块,并利用其子模块over_sampling中的SMOTE“类”实现新样本的生成。有关该“类”的语法和参数含义如下:
SMOTE(ratio=’auto’, random_state=None, k_neighbors=5, m_neighbors=10,
out_step=0.5, kind=’regular’, svm_estimator=None, n_jobs=1)
ratio:用于指定重抽样的比例,如果指定字符型的值,可以是’minority’,表示对少数类别的样本进行抽样、’majority’,表示对多数类别的样本进行抽样、’not minority’表示采用欠采样方法、’all’表示采用过采样方法,默认为’auto’,等同于’all’和’not minority’;如果指定字典型的值,其中键为各个类别标签,值为类别下的样本量;
random_state:用于指定随机数生成器的种子,默认为None,表示使用默认的随机数生成器;
k_neighbors:指定近邻个数,默认为5个;
m_neighbors:指定从近邻样本中随机挑选的样本个数,默认为10个;
kind:用于指定SMOTE算法在生成新样本时所使用的选项,默认为’regular’,表示对少数类别的样本进行随机采样,也可以是’borderline1’、’borderline2’和’svm’;
svm_estimator:用于指定SVM分类器,默认为sklearn.svm.SVC,该参数的目的是利用支持向量机分类器生成支持向量,然后再生成新的少数类别的样本;
n_jobs:用于指定SMOTE算法在过采样时所需的CPU数量,默认为1表示仅使用1个CPU运行算法,即不使用并行运算功能;
分类算法的应用实战
本次分享的数据集来源于德国某电信行业的客户历史交易数据,该数据集一共包含条4,681记录,19个变量,其中因变量churn为二元变量,yes表示客户流失,no表示客户未流失;剩余的自变量包含客户的是否订购国际长途套餐、语音套餐、短信条数、话费、通话次数等。接下来就利用该数据集,探究非平衡数据转平衡后的效果。
# 导入第三方包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import tree
from sklearn import metrics
from imblearn.over_sampling import SMOTE# 读取数据churn = pd.read_excel(r'C:\Users\Administrator\Desktop\Customer_Churn.xlsx') churn.head()
# 中文乱码的处理
plt.rcParams['font.sans-serif']=['Microsoft YaHei']# 为确保绘制的饼图为圆形,需执行如下代码
plt.axes(aspect = 'equal')
# 统计交易是否为欺诈的频数
counts = churn.churn.value_counts()# 绘制饼图
plt.pie(x = counts, # 绘图数据 labels=pd.Series(counts.index).map({'yes':'流失','no':'未流失'}), # 添加文字标签 autopct='%.2f%%' # 设置百分比的格式,这里保留一位小数 )
# 显示图形
plt.show()
如上图所示,流失用户仅占到8.3%,相比于未流失用户,还是存在比较大的差异的。可以认为两种类别的客户是失衡的,如果直接对这样的数据建模,可能会导致模型的结果不够准确。不妨先对该数据构建随机森林模型,看看是否存在偏倚的现象。
原始数据表中的state变量和Area_code变量表示用户所属的“州”和地区编码,直观上可能不是影响用户是否流失的重要原因,故将这两个变量从表中删除。除此,用户是否订购国际长途业务international_plan和语音业务voice_mail_plan,属于字符型的二元值,它们是不能直接代入模型的,故需要转换为0-1二元值。
# 数据清洗
# 删除state变量和area_code变量
churn.drop(labels=['state','area_code'], axis = 1, inplace = True)# 将二元变量international_plan和voice_mail_plan转换为0-1哑变量
churn.international_plan = churn.international_plan.map({'no':0,'yes':1}) churn.voice_mail_plan = churn.voice_mail_plan.map({'no':0,'yes':1}) churn.head()
如上表所示,即为清洗后的干净数据,接下来对该数据集进行拆分,分别构建训练数据集和测试数据集,并利用训练数据集构建分类器,测试数据集检验分类器:
# 用于建模的所有自变量
predictors = churn.columns[:-1]
# 数据拆分为训练集和测试集
X_train,X_test,y_train,y_test = model_selection.train_test_split(churn[predictors], churn.churn, random_state=12)# 构建决策树
dt = tree.DecisionTreeClassifier(n_estimators = 300) dt.fit(X_train,y_train)
# 模型在测试集上的预测
pred = dt.predict(X_test)# 模型的预测准确率
print(metrics.accuracy_score(y_test, pred))
# 模型评估报告
print(metrics.classification_report(y_test, pred))
如上结果所示,决策树的预测准确率超过93%,其中预测为no的覆盖率recall为97%,但是预测为yes的覆盖率recall却为62%,两者相差甚远,说明分类器确实偏向了样本量多的类别(no)。
# 绘制ROC曲线
# 计算流失用户的概率值,用于生成ROC曲线的数据
y_score = dt.predict_proba(X_test)[:,1] fpr,tpr,threshold = metrics.roc_curve(y_test.map({'no':0,'yes':1}), y_score)# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)
# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.3f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity') plt.ylabel('Sensitivity')
# 显示图形
plt.show()
如上图所示,ROC曲线下的面积为0.795,AUC的值小于0.8,故认为模型不太合理。(通常拿AUC与0.8比较,如果大于0.8,则认为模型合理)。接下来,利用SMOTE算法对数据进行处理:
# 对训练数据集作平衡处理
over_samples = SMOTE(random_state=1234) over_samples_X,over_samples_y = over_samples.fit_sample(X_train, y_train)# 重抽样前的类别比例
print(y_train.value_counts()/len(y_train))
# 重抽样后的类别比例
print(pd.Series(over_samples_y).value_counts()/len(over_samples_y))
如上结果所示,对于训练数据集本身,它的类别比例还是存在较大差异的,但经过SMOTE算法处理后,两个类别就可以达到1:1的平衡状态。下面就可以利用这个平衡数据,重新构建决策树分类器了:
# 基于平衡数据重新构建决策树模型
dt2 = ensemble.DecisionTreeClassifier(n_estimators = 300) dt2.fit(over_samples_X,over_samples_y)
# 模型在测试集上的预测
pred2 =dt2.predict(np.array(X_test))# 模型的预测准确率
print(metrics.accuracy_score(y_test, pred2))
# 模型评估报告
print(metrics.classification_report(y_test, pred2))
如上结果所示,利用平衡数据重新建模后,模型的准确率同样很高,为92.6%(相比于原始非平衡数据构建的模型,准确率仅下降1%),但是预测为yes的覆盖率提高了10%,达到72%,这就是平衡带来的好处。
# 计算流失用户的概率值,用于生成ROC曲线的数据
y_score = rf2.predict_proba(np.array(X_test))[:,1] fpr,tpr,threshold = metrics.roc_curve(y_test.map({'no':0,'yes':1}), y_score)
# 计算AUC的值
roc_auc = metrics.auc(fpr,tpr)
# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
# 添加边际线
plt.plot(fpr, tpr, color='black', lw = 1)
# 添加对角线
plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
# 添加文本信息
plt.text(0.5,0.3,'ROC curve (area = %0.3f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity') plt.ylabel('Sensitivity')# 显示图形 电动叉车
plt.show()
教你用Python解决非平衡数据问题(附代码)的更多相关文章
- Python解决八皇后问题的代码【解读】
八皇后问题 来自于西方象棋(现在叫 国际象棋,英文chess),详情可见百度百科. 在西方象棋中,有一种叫做皇后的棋子,在棋盘上,如果双方的皇后在同一行.同一列或同一斜线上,就会互相攻击. 八皇后问题 ...
- 手把手教你用Python实现“坦克大战”,附详细代码!
小时候玩的“坦克大战”,你还记得吗? 满满的回忆 ! 今天,我们使用Python以及强大的第三方库来实现一个简单的坦克大战游戏. 整体效果 环境依赖 python3.7 pygame1.9.6 ...
- 用Python实现BP神经网络(附代码)
用Python实现出来的机器学习算法都是什么样子呢? 前两期线性回归及逻辑回归项目已发布(见文末链接),今天来讲讲BP神经网络. BP神经网络 全部代码 https://github.com/lawl ...
- 解决charles中文乱码(附代码)
1. 将下面的代码保存为一个*.xml的文件 <?xml version='1.0' encoding='UTF-8' ?> <?charles serialisation-vers ...
- 教你用Python实现简单监督学习算法
教你用Python实现简单监督学习算法 监督学习作为运用最广泛的机器学习方法,一直以来都是从数据挖掘信息的重要手段.即便是在无监督学习兴起的近日,监督学习也依旧是入门机器学习的钥匙. 这篇监督学习教程 ...
- 手把手教你吧Python应用到实际开发 不再空谈悟法✍✍✍
手把手教你吧Python应用到实际开发 不再空谈悟法 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问 ...
- 手把手教你把Python应用到实际开发 不再空谈语法
手把手教你把Python应用到实际开发 不再空谈语法 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问 ...
- 手把手教你用Python抓取AWS的日志(CloudTrail)数据
数据时代,利用数据做决策是大数据的核心价值. 本文手把手,教你使用python进行AWS的CloudTrail配置,进行日志抓取.进行数据分析,发现数据价值! 如今是云的时代,许多公司都把自己的IT架 ...
- 12岁的少年教你用Python做小游戏
首页 资讯 文章 频道 资源 小组 相亲 登录 注册 首页 最新文章 经典回顾 开发 设计 IT技术 职场 业界 极客 创业 访谈 在国外 - 导航条 - 首页 最新文章 经典回顾 开发 ...
随机推荐
- cmdb截图
- Kafka设计解析(六)Kafka高性能架构之道
转载自 技术世界,原文链接 Kafka设计解析(六)- Kafka高性能架构之道 本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和 ...
- PAT乙级1030
1030 完美数列 (25 分) 给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列. 现在给定参数 p 和一些正整数,请你从中选择 ...
- 算法练习——最长公共子序列的问题(LCS)
问题描述: 对于两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列.X Y 各自字符串有顺序,但是不一定需要相邻. 最长公共子串(Longest Common Subst ...
- 【OC底层】KVC原理
定义 KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性 常见的API有: - (void)setValue:(id)value forKeyPath: ...
- 面向对象之final关键字
1.1 final的概念 final是个修饰符,它可以用来修饰类,类的成员,以及局部变量.不能修饰构造方法. 问题: 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之 ...
- Linux学习笔记(第五章)
第五章-常用指令 下达指令: 1.[Tab] 2.man + (指令):显示操作说明 开头代号 man page 常用按键
- QQ开发技术资料集锦
1.GG2013:可在广域网部署运行的QQ高仿版 http://www.cnblogs.com/justnow/category/503400.html 2. 苏飞博客: C#仿QQ皮肤-皮肤控件窗体 ...
- 为eclipse添加源代码
看到这个页面,直接点击 红色区域 attach source 关联源代码,进入到如下页面: 点击第二个选择外部的路径,点击导入文件夹,也就是解压出来的src文件夹(不建议直接导整个jar包,虽然也可以 ...
- Oracle的 EXEC SQL CONTEXT学习
磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL杂记页 回到顶级页面:PostgreSQL索引页 [作者 高健@博客园 luckyjackgao@gmail. ...