信用卡欺诈预测——模型调优
一、背景介绍
这个数据来自欧洲信用卡交易数据,总共包括两天的交易数据。在284,807次交易中发现了492例诈骗。数据集极其不平衡,诈骗频率只占了交易频次的0.172%。
二、观察数据
1.数据源
本文的数据源从Kaggle官方网站下载,该数据集共计284807条数据,变量总数为31个。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df1 = pd.read_csv('creditcard.csv')
df1['Class'].value_counts()
2. 目标变量
通过平台描述和数据框查看,V1,V2,…V28是主成分,Time和Amount是没有经过PCA处理的。Time是每次交易与第一次交易之间距离的时间,以秒计。Amount代表消费金额,Class代表响应变量,1代表欺诈,0代表正常,除此之外没有缺失数据。
三、采样处理
通过数据可视化可以看出,数据中欺诈样本占比极小,在284807次交易中仅有492例欺诈,说明该数据属于不均衡样本,对于不平衡样本的处理方法有很多,比如:
- 欠采样(从好样本里面随机抽取与坏样本同样多的数据进行模型拟合,但是抛弃了大数据好样本的数据,可能会造成较大的偏差)
- 过采样(将坏样本反复抽取并生成与好样本同样多的数据进行模型拟合,只是单纯的重复了正例,可能会过拟合)
- SMOTE算法(本质是过采样,通过在局部区域进行K-近邻生成了新的坏样本,可以理解为是一种集成学习,但是也可能会过拟合)
这里主要采用的是欠采样方法对样本进行预处理后,导入到逻辑回归模型中,并对模型进行评估。
四、模型评估
1.正则惩罚项系数
逻辑回归是一个分类评定模型,它与回归模型结合较为紧密,因此虽然是分类器,但也常称作“回归”。其实现方法与原理是将线性回归或者非线性回归的“最大似然估计”作为参数,传入分类**函数,一般是sigmoid函数。逻辑回归模型中有个重要的参数C:正则惩罚项系数,初步调整该系数采用的方法是分别选取0.01,0.1,1,10,100这五个参数,以召回率作为评估标准,选取评分最高的C参数,故C值为0.01。
def print_Kfold_scores(x_train_data,y_train_data):
fold = KFold(len(y_train_data),5,shuffle=False)
# 定义正则化惩罚项的系数(待选)
c_param_range = [0.01,0.1,1,10,100]
results_table = pd.DataFrame(index=range(len(c_param_range)),columns=['C_parameter','Mean_recall_score'])
results_table['C_parameter'] = c_param_range
j = 0
for c_param in c_param_range:
print('--------------------')
print('c_parameter:',c_param)
print('--------------------')
recall_accs = []
for iteration,indices in enumerate(fold,start=1):
# 从已有参数建立逻辑回归模型
lr = LogisticRegression(C = c_param,penalty = 'l1')
# 用训练数据带入回归模型
lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
# 用得到的模型预测数据
y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:].values)
# 计算预测精度
recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)
recall_accs.append(recall_acc)
print('iteration',iteration,':recall score =',recall_acc)
# 评估分数的平均值就是我们想得到的度量标准
# 此处用ix会报错,未知原因,所以换位loc
results_table.loc[j,'Mean_recall_score'] = np.mean(recall_accs)
j += 1
print()
print('Mean_recall_score',np.mean(recall_accs))
print()
return results_table
训练集数据的混淆矩阵可以回看出,虽然召回率为89.6%,但有20606名正常客户判断为有问题的用户。
2.阈值
在sklearn包的逻辑回归模型中,其默认分类**函数是:
这个函数的大致图像如下:
一般情况下,模型的阈值为0.5,即概率大于0.5的分为1,反之为0,但当阈值偏小时,会导致划分为1的数据偏多,所以通过改变阈值来改变模型结果。
lr = LogisticRegression(C=0.01,penalty='l1')
lr.fit(x_train_under,y_train_under.values.ravel())
y_pred_undersample_probability = lr.predict_proba(x_test_under.values)
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
plt.figure(figsize=(15,10))
j = 1
for i in thresholds:
y_test_predictions_high_recall=y_pred_undersample_probability[:,1] > i
plt.subplot(3,3,j)
j += 1
cnf_matrix = confusion_matrix(y_test_under,y_test_predictions_high_recall)
np.set_printoptions(precision=2)
print('Recall metric in the testing dataset while threshold=%s:'%i,cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
# 画出混淆矩阵
class_names = [0,1]
plot_confusion_matrix(cnf_matrix,classes=class_names,title='Threshold >= %s'%i)
plt.show()
提高阈值,召回率不断提高,但阈值到0.7后,召回率已经过高,所以选取阈值为0.7和0.8进行比较。
y_train_high_recall = y_train_probability[:,1] > .7
cnf_matrix = confusion_matrix(y_train,y_train_high_recall)
np.set_printoptions(precision=2)
print('Recall metric in the testing dataset while threshold=0.7:',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
print('Precision in the testing dataset while threshold=0.7:',
(cnf_matrix[1,1]+cnf_matrix[0,0])/(cnf_matrix[1,0]+cnf_matrix[1,1]+cnf_matrix[0,1]+cnf_matrix[0,0]))
plt.figure(figsize=(8,5))
class_names = [0,1]
plot_confusion_matrix(cnf_matrix,classes=class_names,title='Threshold = 0.7')
plt.show()
阈值为0.7的情况如下:
阈值为0.8的情况如下:
和阈值0.8相比,阈值为0.7的召回率相近,所以最终确定阈值为0.7。最后用测试集验证一下,其结果召回率为99.6%。