Python大数据分析——AdaBoost、GBDT、SMOTE与XGBoost算法模型
Python大数据分析——Adaboost、GBDT与XGBoost算法模型
- AdaBoost模型
- 介绍
- 损失函数
- 步骤
- 函数
- GBDT模型
- 介绍
- 步骤
- 函数
- SMOTE模型
- 非平衡数据特征
- 介绍
- 步骤
- 实例
- 函数
- XGBoost模型
- 介绍
- 损失函数
- 泰勒展开式
- 损失函数演变
- 函数
- 实例
- 信用卡违约
- AdaBoost
- GBDT
- XGBoost
AdaBoost模型
介绍
提升树算法与线性回归模型的思想类似,所不同的是该算法实现了多棵基础决策树f(x)的加权运算,最具代表的提升树为AdaBoost算法,即:
其中,F(x)是由M棵基础决策树构成的最终提升树,Fm-1(x)表示经过m-1轮迭代后的提升树,αm为第m棵基础决策树所对应的权重,fm(x)为第m棵基础决策树。
其中Fm-1(x)=α1f1+α2f2+…+αm-1fm-1
对于Adaboost算法而言,每一棵基础决策树都是基于前一棵基础决策树的分类结果对样本点设置不同的权重,如果在前一棵基础决策树中将某样本点预测错误,就会增大该样本点的权重,否则会相应降低样本点的权重,进而再构建下一棵基础决策树,更加关注权重大的样本点。
所以,AdaBoost算法需要解决三大难题,即样本点的权重wmi如何确定、基础决策树f(x)如何选择以及每一棵基础决策树所对应的权重αm如何计算。
损失函数
exp(x)=e**x 自然指数函数
wmi是指预测错误率
进一步化简:
对其求偏导,令其为0:
步骤
函数
AdaBoostClassifier(base_estimator=None, n_estimators=50, learning_rate=1.0, algorithm=‘SAMME.R’, random_state=None) # 分类问题
AdaBoostRegressor(base_estimator=None, n_estimators=50, learning_rate=1.0, loss=‘linear’, random_state=None) # 回归问题
base_estimator:用于指定提升算法所应用的基础分类器,默认为分类决策树(CART),也可以是其他基础分类器,但分类器必须支持带样本权重的学习,如神经网络。
n_estimators:用于指定基础分类器的数量,默认为50个,当模型在训练数据集中得到完美的拟合后,可以提前结束算法,不一定非得构建完指定个数的基础分类器。
learning_rate:用于指定模型迭代的学习率或步长,即对应的提升模型F(x)可以表示为F(x)= Fm-1(x)+ vamfm(x),其中的v就是该参数的指定值,默认值为1;对于较小的学习率v而言则需要迭代更多次的基础分类器,通常情况下需要利用交叉验证法确定合理的基础分类器个数和学习率。
algorithm:用于指定AdaBoostClassifier分类器的算法,默认为’SAMME.R’,也可以使用’SAMME’;使用’SAMME.R’时,基础模型必须能够计算类别的概率值;一般而言,‘SAMME.R’算法相比于’SAMME’算法,收敛更快、误差更小、迭代数量更少。
loss:用于指定AdaBoostRegressor回归提升树的损失函数,可以是’linear’,表示使用线性损失函数;也可以是’square’,表示使用平方损失函数;还可以是’exponential’,表示使用指数损失函数;该参数的默认值为’linear’。
random_state:用于指定随机数生成器的种子。
GBDT模型
介绍
梯度提升树算法实际上是提升算法的扩展版,在原始的提升算法中,如果损失函数为平方损失或指数损失,求解损失函数的最小值问题会非常简单,但如果损失函数为更一般的函数,目标值的求解就会相对复杂很多。GBDT就是用来解决这个问题,利用损失函数的负梯度值作为该轮基础模型损失值的近似,并利用这个近似值构建下一轮基础模型。
步骤
函数
GradientBoostingClassifier(loss=‘ls’, learning_rate=0.1, n_estimators=100, min_samples_split=2, min_samples_leaf=1, max_depth=3, min_impurity_decrease=0.0, init=None, max_features=None, max_leaf_nodes=None)
loss:用于指定GBDT算法的损失函数,对于分类的GBDT,可以选择’deviance’和’exponential’,分别表示对数似然损失函数和指数损失函数;对于预测的GBDT,可以选择’ls’ ‘lad’ ‘huber’和’quantile’,分别表示平方损失函数、绝对值损失函数、Huber损失函数(前两种损失函数的结合,当误差较小时,使用平方损失,否则使用绝对值损失,误差大小的度量可使用alpha参数指定)和分位数回归损失函数(需通过alpha参数设定分位数)。
learning_rate:用于指定模型迭代的学习率或步长,即对应的梯度提升模型F(x)可以表示为F_M(x) = F_M - 1(x) + vf_m(x):,其中的v就是该参数的指定值,默认值为0.1;对于较小的学习率v而言,则需要迭代更多次的基础分类器,通常情况下需要利用交叉验证法确定合理的基础模型的个数和学习率。
n_estimators:用于指定基础模型的数量,默认为100个。
min_samples_split:用于指定每个基础模型的根节点或中间节点能够继续分割的最小样本量,默认为2。
min_samples_leaf:用于指定每个基础模型的叶节点所包含的最小样本量,默认为1。
min_weight_fraction_leaf:用于指定每个基础模型叶节点最小的样本权重,默认为0,表示不考虑叶节点的样本权值。
max_depth:用于指定每个基础模型所包含的最大深度,默认为3层。
min_impurity_decrease:用于指定每个基础模型的节点是否继续分割的最小不纯度,默认为0;如果不纯度超过指定的阈值,则节点需要分割,否则不分割。
init:用于指定初始的基础模型,用于执行初始的分类或预测。
max_features:用于指定每个基础模型所包含的最多分割字段数,默认为None,表示分割时使用所有的字段;如果为具体的整数,则考虑使用对应的分割字段数;如果为0~1的浮点数,则考虑对应百分比的字段个数;如果为’sqrt’,则表示最多考虑√P个字段,与指定’auto’效果一致;如果为’log2’,则表示最多使用log₂P个字段。其中,P表示数据集所有自变量的个数。
max_leaf_nodes:用于指定每个基础模型最大的叶节点个数,默认为None,表示对叶节点个数不做任何限制。
SMOTE模型
针对的是非平衡数据的处理!
非平衡数据特征
在实际应用中,类别型的因变量可能存在严重的偏倚,即类别之间的比例严重失调。如欺诈问题中欺诈类观测在样本集中毕竟占少数:客户流失问题中,忠实的客户往往也是占很少一部分;在某营销活动的响应问题中,真正参与活动的客户也同样只是少部分。
如果数据存在严重的不平衡,预测得出的结论往往也是有偏的,即分类结果会偏向于较多观测的类。为了解决数据的非平衡问题,2002年Chawla提出了SMOTE算法,即合成少数过采样技术,它是基于随机过采样算法的一种改进方案。
介绍
SMOTE算法的基本思想就是对少数类别样本进行分析和模拟,并将人工模拟的新样本添加到数据集中,进而使原始数据中的类别不再严重失衡。
步骤
- 采样最邻近算法,计算出每个少数类样本的K个近邻。
- 从K个近邻中随机挑选N个样本进行随机线性插值。
- 构造新的少数类样本。
- 将新样本与原数据合成,产生新的训练集。
实例
(1)利用KNN算法,选择离样本点x1最近的K个同类样本点(不妨最近邻为5)。
(2) 从最近的K个同类样本点中,随机挑选M个样本点(不妨设M为2),M的选择依赖于最终所希望的平衡率。
(3)对于每一个随机选中的样本点,构造新的样本点。新样本点的构造需要使用下方的公式:
其中,xix_{i}xi表示少数类别中的一个样本点(如图中五角星所代表的x1x_{1}x1样本);xjx_{j}xj表示从K近邻中随机挑选的样本点jjj;rand(0,1)rand(0,1)rand(0,1)表示生成0~1的随机数。
假设图中样本点x1x_{1}x1的观测值为(2,3,10,7)(2,3,10,7)(2,3,10,7),从图中的5个近邻随机挑选两个样本点,它们的观测值分别为(1,1,5,8)(1,1,5,8)(1,1,5,8)和(2,1,7,6)(2,1,7,6)(2,1,7,6),由此得到的两个新样本点为:
xnew1=(2,3,10,7)+0.3×((1,1,5,8)−(2,3,10,7))=(1.7,2.4,8.5,7.3)x_{new1}=(2,3,10,7)+0.3\times((1,1,5,8)-(2,3,10,7))=(1.7,2.4,8.5,7.3)xnew1=(2,3,10,7)+0.3×((1,1,5,8)−(2,3,10,7))=(1.7,2.4,8.5,7.3)
xnew2=(2,3,10,7)+0.26×((2,1,7,6)−(2,3,10,7))=(2.48,9.22,6.74)x_{new2}=(2,3,10,7)+0.26\times((2,1,7,6)-(2,3,10,7))=(2.48,9.22,6.74)xnew2=(2,3,10,7)+0.26×((2,1,7,6)−(2,3,10,7))=(2.48,9.22,6.74)
(4)重复步骤(1)、通过迭代少数类别中的每(2)和(3),一个样本xi,最终将原始的少数类别样本量扩大为理想的比例。
函数
SMOTE(ratio=‘auto’, random_state=None, k_neighbors=5, m_neighbors=10)
ratio:用于指定重抽样的比例,如果指定字符型的值,可以是’minority’(表示对少数类别的样本进行抽样)、‘majority’(表示对多数类别的样本进行抽样)、‘not minority’(表示采用欠采样方法)、‘all’(表示采用过采样方法),默认为’auto’,等同于’all’和’not minority’。如果指定字典型的值,其中键为各个类别标签,值为类别下的样本量。
random_state:用于指定随机数生成器的种子,默认为None,表示使用默认的随机数生成器。
k_neighbors:指定近邻个数,默认为5个。
m_neighbors:指定从近邻样本中随机挑选的样本个数,默认为10个。
XGBoost模型
XGBoost算法是根据GBDT算法改良而来
介绍
XGBoost是由传统的GBDT模型发展而来的,GBDT模型在求解最优化问题时应用了一阶导技术,而XGBoost则使用损失函数的一阶和二阶导,而且可以自定义损失函数,只要损失函数可一阶和二阶求导。
XGBoost算法相比于GBDT算法还有其他优点,例如支持并行计算,大大提高算法的运行效率;XGBoost在损失函数中加入了正则项,用来控制模型的复杂度,进而可以防止模型的过拟合;XGBoost除了支持CART基础模型,还支持线性基础模型;XGBoost采用了随机森林的思想,对字段进行抽样,既可以防止过拟合,也可以降低模型的计算量。
损失函数
其中,y^i(t)\hat{y}_i^{(t)}y^i(t)表示经第ttt轮迭代后的模型预测值,y^i(t−1)\hat{y}_i^{(t - 1)}y^i(t−1)表示已知t−1t - 1t−1个基础模型的预测值,ft(xi)f_t(x_i)ft(xi)表示第ttt个基础模型。
对于集成树,关键点就是第ttt个基础模型ftf_tft的选择。所以,只需要寻找一个能够使目标函数尽可能最大化降低的ftf_tft即可,故构造的目标函数如下:
损失函数中的Ω(fj)\Omega(f_j)Ω(fj)为第jjj个基础模型的正则项,用于控制模型的复杂度。为了简单起见,不妨将损失函数LLL表示为平方损失,则如上的目标函数可以表示为:
由于前t−1t - 1t−1个基础模型是已知的,故y^i(t−1)\hat{y}_i^{(t - 1)}y^i(t−1)的预测值也是已知的,同时前t−1t - 1t−1个基础模型的复杂度也是已知的,故不妨将所有的已知项设为常数constantconstantconstant,则目标函数可以重新表达为:
其中,(y^i(t−1)−yi)(\hat{y}_i^{(t - 1)} - y_i)(y^i(t−1)−yi)项就是前t−1t - 1t−1个基础模型所产生的残差,说明目标函数的选择与前t−1t - 1t−1个基础模型的残差相关,这一点与GBDT是相同的。如上是假设损失函数为平方损失,对于更一般的损失函数来说,可以使用泰勒展开对损失函数值做近似估计。
泰勒展开式
其中,f(x)f(x)f(x)是一个具有二阶可导的函数,f(x)′f(x)'f(x)′为f(x)f(x)f(x)的一阶导函数,f(x)′′f(x)''f(x)′′为f(x)f(x)f(x)的二阶导函数,Δx\Delta xΔx为f(x)f(x)f(x)在某点处的变化量。假设令损失函数LLL为泰勒公式中的fff,令损失函数中y^i(t−1)\hat{y}_i^{(t - 1)}y^i(t−1)项为泰勒公式中的xxx,令损失函数中ft(xi)f_t(x_i)ft(xi)项为泰勒公式中的Δx\Delta xΔx,则目标函数Obj(t)Obj^{(t)}Obj(t)可以近似表示为:
在上式中,gig_igi和hih_ihi分别是损失函数L(yi,y^i(t−1))L(y_i,\hat{y}_i^{(t - 1)})L(yi,y^i(t−1))关于y^i(t−1)\hat{y}_i^{(t - 1)}y^i(t−1)的一阶导函数值和二阶导函数值,即它们可以表示为:
损失函数演变
通过泰勒展开和常数项,我们的目标函数就会转化成对于正则项求解:
假设基础模型ftf_tft由CART树构成,对于一棵树来说,它可以被拆分为结构部分qqq,以及叶子节点所对应的输出值www。可以利用这两部分反映树的复杂度,即复杂度由树的叶子节点个数(反映树的结构)和叶子节点输出值的平方构成:
其中,TTT表示叶子节点的个数,wj2w_j^2wj2表示输出值向量的平方。CART树生长得越复杂,对应的TTT越大,Ω(ft)\Omega(f_t)Ω(ft)也越大。
对其目标函数进行简化:
其中,Gj=∑i∈IjgiG_j = \sum_{i\in I_j}g_iGj=∑i∈Ijgi;Hj=∑i∈IjhiH_j = \sum_{i\in I_j}h_iHj=∑i∈Ijhi。它们分别表示所有属于叶子节点jjj的样本点对应的gig_igi之和以及hih_ihi之和。所以,最终是寻找一个合理的ftf_tft,使得式子∑j=1T(Gjwj+12(Hj+λ)wj2)+γT\sum_{j = 1}^{T}(G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2)+\gamma T∑j=1T(Gjwj+21(Hj+λ)wj2)+γT尽可能大地减小。
求偏导,令导函数为0
所以,将wjw_jwj的值导入到目标函数Obj(t)Obj^{(t)}Obj(t)中,可得:
函数
XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100, objective=‘binary:logistic’, booster=‘gbtree’, gamma=0, min_child_weight=1, reg_alpha=0, reg_lambda=1, missing=None)
max_depth:用于指定每个基础模型所包含的最大深度,默认为3层。learning_rate:用于指定模型迭代的学习率或步长,默认为0.1,即对应的梯度提升模型FT(x)F_T(x)FT(x)可以表示为FT(x)=FT−1(x)+vft(x)F_T(x)=F_{T - 1}(x)+vf_t(x)FT(x)=FT−1(x)+vft(x),其中的vvv就是该参数的指定值,默认值为1;对于较小的学习率vvv而言,则需要迭代更多次的基础分类器,通常情况下需要利用交叉验证法确定合理的基础模型的个数和学习率。
n_estimators:用于指定基础模型的数量,默认为100个。
objective:用于指定目标函数中的损失函数类型,对于分类型的XGBoost算法,默认的损失函数为二分类的Logistic损失(模型返回概率值),也可以是’multi:softmax’,表示用于处理多分类的损失函数(模型返回类别值),还可以是’multi:softprob’,与’multi:softmax’相同,所不同的是模型返回各类别对应的概率值;对于预测型的XGBoost算法,默认的损失函数为线性回归损失。
booster:用于指定基础模型的类型,默认为’gbtree’,即CART模型,也可以是’gblinear’,表示基础模型为线性模型。
gamma:用于指定节点分割所需的最小损失函数下降值,即增益值Gain的阈值,默认为0。
min_child_weight:用于指定叶子节点中各样本点二阶导之和的最小值,即HjH_jHj的最小值,默认为1,该参数的值越小,模型越容易过拟合。
reg_alpha:用于指定L1正则项的系数,默认为0。
reg_lambda:用于指定L2正则项的系数,默认为1。
missing:用于指定缺失值的表示方法,默认为None,表示NaN即为默认值。
实例
信用卡违约
- 查看数据
主要是查看类别是否不平衡。
# 导入第三方包
import pandas as pd
import matplotlib.pyplot as plt# 读入数据
default = pd.read_excel(r'D:\pythonProject\data\default of credit card.xls')# 数据集中是否违约的客户比例
# 为确保绘制的饼图为圆形,需执行如下代码
plt.axes(aspect = 'equal')
# 中文乱码和坐标轴负号的处理
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 统计客户是否违约的频数
counts = default.y.value_counts()
# 绘制饼图
plt.pie(x = counts, # 绘图数据labels=pd.Series(counts.index).map({0:'不违约',1:'违约'}), # 添加文字标签autopct='%.1f%%' # 设置百分比的格式,这里保留一位小数)
# 显示图形
plt.show()
输出:
还算较为平衡,如果为9:1或者更甚那么就属于不平衡。
AdaBoost
- 数据集拆分与构建AdaBoost分类应用
# 将数据集拆分为训练集和测试集
# 导入第三方包
from sklearn import model_selection
from sklearn import ensemble
from sklearn import metrics# 排除数据集中的ID变量和因变量(没用的变量),剩余的数据用作自变量X
X = default.drop(['ID','y'], axis = 1)
y = default.y
# 数据拆分
X_train,X_test,y_train,y_test = model_selection.train_test_split(X,y,test_size = 0.25, random_state = 1234)# 构建AdaBoost算法的类
AdaBoost1 = ensemble.AdaBoostClassifier()
# 算法在训练数据集上的拟合
AdaBoost1.fit(X_train,y_train)
# 算法在测试数据集上的预测
pred1 = AdaBoost1.predict(X_test)# 返回模型的预测效果
print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred1))
print('模型的评估报告:\n',metrics.classification_report(y_test, pred1))
输出:
- ROC曲线
# 计算客户违约的概率值,用于生成ROC曲线的数据
y_score = AdaBoost1.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, 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.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
输出:
没有达到0.8,我们就可以认为模型不太可以。
如果说假如AdaBoost模型可以,我们可以做:
- 挑选出重要的变量
# 自变量的重要性排序
importance = pd.Series(AdaBoost1.feature_importances_, index = X.columns)
importance.sort_values().plot(kind = 'barh')
plt.show()
我们通过设置阈值来判断重要与不重要,然后取重要的变量进行建模,并进行参数调优
# 取出重要性比较高的自变量建模
predictors = list(importance[importance>0.02].index)
predictors# 通过网格搜索法选择基础模型所对应的合理参数组合
# 导入第三方包
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
import sklearn.ensemble as ensemble # 确保导入了ensemble模块max_depth = [3,4,5,6]
params1 = {'estimator__max_depth': max_depth} # 将base_estimator__改为estimator__# 使用estimator参数替代base_estimator
base_model = GridSearchCV(estimator=ensemble.AdaBoostClassifier(estimator=DecisionTreeClassifier()),param_grid=params1, scoring='roc_auc', cv=5, n_jobs=4, verbose=1
)
base_model.fit(X_train[predictors], y_train)# 返回参数的最佳组合和对应AUC值
base_model.best_params_, base_model.best_score_
输出:
Fitting 5 folds for each of 4 candidates, totalling 20 fits
({‘estimator__max_depth’: 3}, 0.7417465487923727)
对基础树的树的数量进行调整:
# 通过网格搜索法选择提升树的合理参数组合
# 导入第三方包
from sklearn.model_selection import GridSearchCVn_estimators = [100,200,300]
learning_rate = [0.01,0.05,0.1,0.2]
params2 = {'n_estimators':n_estimators,'learning_rate':learning_rate}# 将base_estimator改为estimator
adaboost = GridSearchCV(estimator = ensemble.AdaBoostClassifier(estimator = DecisionTreeClassifier(max_depth = 3)),param_grid= params2, scoring = 'roc_auc', cv = 5, n_jobs = 4, verbose = 1
)
adaboost.fit(X_train[predictors] ,y_train)# 返回参数的最佳组合和对应AUC值
adaboost.best_params_, adaboost.best_score_
输出:
Fitting 5 folds for each of 12 candidates, totalling 60 fits
({‘learning_rate’: 0.05, ‘n_estimators’: 100}, 0.7693742071267697)
然后我们观测下模型是否有一个好的提升:
# 使用最佳的参数组合构建AdaBoost模型
AdaBoost2 = ensemble.AdaBoostClassifier(estimator=DecisionTreeClassifier(max_depth=3), # 将base_estimator改为estimatorn_estimators=300, learning_rate=0.01
)
# 算法在训练数据集上的拟合
AdaBoost2.fit(X_train[predictors], y_train)
# 算法在测试数据集上的预测
pred2 = AdaBoost2.predict(X_test[predictors])# 导入metrics模块(确保已导入)
from sklearn import metrics# 返回模型的预测效果
print('模型的准确率为:\n', metrics.accuracy_score(y_test, pred2))
print('模型的评估报告:\n', metrics.classification_report(y_test, pred2))
输出:
发现是有略微提升但不多
# 计算正例的预测概率,用于生成ROC曲线的数据
y_score = AdaBoost2.predict_proba(X_test[predictors])[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, 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.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
输出:
GBDT
那如果它不行,我们使用GBDT模型做尝试:
# 运用网格搜索法选择梯度提升树的合理参数组合
learning_rate = [0.01,0.05,0.1,0.2] # 学习率
n_estimators = [100,300,500] # 基础树的个数
max_depth = [3,4,5,6] # 每一棵树的深度
# 最终能实现4*3*4=48种参数的组合
params = {'learning_rate':learning_rate,'n_estimators':n_estimators,'max_depth':max_depth}
gbdt_grid = GridSearchCV(estimator = ensemble.GradientBoostingClassifier(),param_grid= params, scoring = 'roc_auc', cv = 5, n_jobs = 4, verbose = 1)
gbdt_grid.fit(X_train[predictors],y_train)
# 返回参数的最佳组合和对应AUC值
gbdt_grid.best_params_, gbdt_grid.best_score_
输出:
Fitting 5 folds for each of 48 candidates, totalling 240 fits
({‘learning_rate’: 0.1, ‘max_depth’: 4, ‘n_estimators’: 100},
0.7744112143984061)
然后我们进行预测,看看与AdaBoost相比是否有效果的提升(其中参数的调优我们可以使用网格搜索法)
# 基于最佳参数组合的GBDT模型,对测试数据集进行预测
pred = gbdt_grid.predict(X_test[predictors])
# 返回模型的预测效果
print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred))
print('模型的评估报告:\n',metrics.classification_report(y_test, pred))
输出:
# 计算违约客户的概率值,用于生成ROC曲线的数据
y_score = gbdt_grid.predict_proba(X_test[predictors])[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, 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.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
输出:
XGBoost
运算速度会得到优化;添加了正则项实现了非过拟合处理,让模型具有更强的泛化性
# 读入数据
creditcard = pd.read_csv(r'D:\pythonProject\data\creditcard.csv')
# 为确保绘制的饼图为圆形,需执行如下代码
plt.axes(aspect = 'equal')
# 统计交易是否为欺诈的频数
counts = creditcard.Class.value_counts()
# 绘制饼图
plt.pie(x = counts, # 绘图数据labels=pd.Series(counts.index).map({0:'正常',1:'欺诈'}), # 添加文字标签autopct='%.2f%%' # 设置百分比的格式,这里保留一位小数)
# 显示图形
plt.show()
输出:
发现为非平衡数据,我们需要利用SMOTE方法对数据进行平衡化:
# 将数据拆分为训练集和测试集
# 删除自变量中的Time变量
X = creditcard.drop(['Time','Class'], axis = 1)
y = creditcard.Class
# 数据拆分
X_train,X_test,y_train,y_test = model_selection.train_test_split(X,y,test_size = 0.3, random_state = 1234)
# 导入第三方包
from imblearn.over_sampling import SMOTE
import pandas as pd# 运用SMOTE算法实现训练数据集的平衡
over_samples = SMOTE(random_state=1234)
# 使用fit_resample替代fit_sample
over_samples_X, over_samples_y = over_samples.fit_resample(X_train.values, y_train.values.ravel())# 重抽样前的类别比例
print(y_train.value_counts()/len(y_train))
# 重抽样后的类别比例
print(pd.Series(over_samples_y).value_counts()/len(over_samples_y))
输出:
然后进行XGB方法
# https://www.lfd.uci.edu/~gohlke/pythonlibs/
# 导入第三方包
import xgboost
import numpy as np
# 构建XGBoost分类器
xgboost = xgboost.XGBClassifier()
# 使用重抽样后的数据,对其建模
xgboost.fit(over_samples_X,over_samples_y)
# 将模型运用到测试数据集中
resample_pred = xgboost.predict(np.array(X_test))# 返回模型的预测效果
print('模型的准确率为:\n',metrics.accuracy_score(y_test, resample_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test, resample_pred))
输出:
# 计算欺诈交易的概率值,用于生成ROC曲线的数据
y_score = xgboost.predict_proba(np.array(X_test))[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, 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.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
输出:
那么我们如果直接用非平衡数据进行建模是怎么样的:
# 构建XGBoost分类器
import xgboost
xgboost2 = xgboost.XGBClassifier()
# 使用非平衡的训练数据集拟合模型
xgboost2.fit(X_train,y_train)
# 基于拟合的模型对测试数据集进行预测
pred2 = xgboost2.predict(X_test)
# 混淆矩阵
pd.crosstab(pred2,y_test)
输出:
# 返回模型的预测效果
print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred2))
print('模型的评估报告:\n',metrics.classification_report(y_test, pred2))
输出:
# 计算欺诈交易的概率值,用于生成ROC曲线的数据
y_score = xgboost2.predict_proba(X_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test, 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.2f)' % roc_auc)
# 添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
# 显示图形
plt.show()
输出:
根据输出的对比,我们能发现确实不如平衡数据的效果好。