用SMOTE算法和XGBoost模型处理信用卡欺诈数据

如果分类问题中类别型的因变量可能严重失衡,例如欺诈问题中,欺诈类观测在样本集中占少数;客户流失问题中,忠实的客户也是往往占很少一部分;某营销活动的响应过程中,真正参与的客户也同样只是少部分。

如果数据存在严重的不平衡,预测得出的结论也是有偏的,即分类结果会偏向于较多观测的类,一般构造1:1的数据,要么将多的那一类砍掉一部分(欠采样),要么将少的那一类进行Bootstrap抽样(过采样),前者会丢失隐含信息,后者会形成简单复制,使模型产生过拟合。
对于不平衡类的分类器评价,使用ROC和AUC作为评价分类器的指标

2002年Chawla提出了SMOTE算法,即合成少数过采样技术,是目前处理不平衡数据的常用手段,对少数类别样本进行分析模拟,并将人工模拟的新样本添加到数据集中,进而使类别不再失衡。利用KNN技术,合成的策略是对每个少数类样本a,从它的最近邻中随机选一个样本b,然后在a、b之间的连线上随机选一点作为新合成的少数类样本。

XGBoost是Gradient Boosting的一种高效系统实现,并不是一种单一算法。xgboos也是以(CART)为基学习器的GB算法,但是扩展和改进了GDBT。相比GBDT的优点有:
(1)xgboost在代价函数里自带加入了正则项,用于控制模型的复杂度。
(2)xgboost在进行节点的分裂时,支持各个特征多线程进行增益计算,因此算法更快,准确率也相对高一些。

XGBoost里面的基学习器除了支持CART基础模型,也可用线性分类器(gblinear)。而GBDT则特指梯度提升决策树算法。另外不同于GBDT使用一阶导,XGBoost可以支持不同的损失函数(用户可以自定义),来优化效果,只要函数一、二阶可导即可。除此之外,支持并行运算,提高运行效率;在损失函数中加了正则项,用来控制模型复杂度,防止过拟合;采用了随机森林的思想,对字段进行抽样,可以防止过拟合,也可以降低模型计算量。

有别于随机森林集成,还有提升算法AdaBoost,梯度提升算法GBDT,升级版的梯度算法XGBoost,。

AdaBoost在解决分类问题时,是通过改变样本点的权重大小,并将各个基础模型按权重实现线性组合,最终得到拟合数据的提升树;在解决预测问题时,每一轮基础模型都是拟合上一轮模型所形成的残差,最终将各个基础模型的预测值相加。
不管是分类提升树,还是回归提升树,都是将各个基础模型以串联的形式构成最终的提升树。
在回归提升树中,如果损失函数使用的是平方损失或者指数损失,目标函数的求解会相对简单,为了能够使提升树试用于更多类型的损失函数,衍生出GBDT,即利用损失函数的导函数作为残差的近似值,方便了运算也提高了提升树的灵活性。
AdaBoost和GBDT在构建目标函数时都没有加入反映模型复杂度的正则项,而XGBoost算法实现了正则化的加入,进而可以防止模型的过拟合,并在求解最优化问题时利用了损失函数的一阶导和二阶导。还可以支持并行计算,支持线性的基础模型,支持建模字段的随机选择等。

# 读入数据
creditcard = pd.read_csv(r'F:\creditcard.csv')
creditcard.head()

因变量Class表示用户在交易中是否存在欺诈行为(1表示欺诈,0表示不欺诈)已对原始数据做了主成分分析处理,只有2个没有做(Time交易时间间隔和Amount交易金额)。

# 为确保绘制的饼图为圆形,需执行如下代码
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

# 运用SMOTE算法实现训练数据集的平衡
over_samples = SMOTE(random_state=1234) 
over_samples_X,over_samples_y = over_samples.fit_sample(X_train, y_train)
#over_samples_X, over_samples_y = over_samples.fit_sample(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))

类别比例达到平衡,构建XGBoost模型(版本受限,XGBoost模块未下载成功,结果未运行)

# 导入第三方包
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))

模型的预测准确率超过99%,而且模型对欺诈交易的覆盖率高达88%(正确预测为欺诈的交易量/实际为欺诈的交易量),对正常交易的覆盖率高达99%,以上为默认参数,还可以利用交叉验证获得更加参数组合,下面运用ROC曲线验证模型在测试集上的表现

# 计算欺诈交易的概率值,用于生成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()

面积AUC高达0.98,拟合效果非常优秀

为了体现SMOTE算法在非平衡数据上的价值,利用XGBoost算法直接在非平衡数据上建模,比较差异

# 构建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))

准确率高达100%,但是是由于数据的不平衡性,导致结果的有偏

基于非平衡数据,也绘制ROC曲线,通过比对AUC的值,对比两个模型的好坏

# 计算欺诈交易的概率值,用于生成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()

AUC的值为0.97,相比平衡数据所构建的模型,AUC值要小0.1,进而验证了利用SMOTE算法实现数据的平衡是有必要的,通过平衡数据,可以获得更加稳定和更具泛化能力的模型。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容