文章目录
0 简介
今天学长向大家介绍一个机器视觉项目
基于大数据的信用卡欺诈检测
🧿 选题指导, 项目分享:见文末
1 数据集
数据集包括了 2013 年 9 月份两天时间内的信用卡交易数据,284807 笔交易中,一共有 492 笔是欺诈行为。输入数据一共包括了 28 个特征 V1,V2,……V28 对应的取值,以及交易时间 Time 和交易金额 Amount。为了保护数据隐私,我们不知道 V1 到 V28 这些特征代表的具体含义,只知道这 28 个特征值是通过 PCA 变换得到的结果。另外字段 Class 代表该笔交易的分类,Class=0 为正常(非欺诈),Class=1 代表欺诈。
目标是针对这个数据集构建一个信用卡欺诈分析的分类器,采用的是逻辑回归
2 分析流程
- 数据探索
- 数据规范化
- 解决样本不平衡问题
在各方案下进行:
- 数据集划分(交叉验证)
- 模型创建
- 模型训练
- 模型评估
3 数据预览
3.1 数据浏览
df = pd.read_csv('data/creditcard.csv')
df.head()
3.1.1 查看数据分布
count_class = df['Class'].value_counts(sort=True)
count_class.plot(kind='bar')
plt.title('Fraud Class histogram')
plt.xlabel('Class')
plt.ylabel('Frequency')
- 数据已经做过特征处理
- 根据任务简单的分析,在通常情况下存在欺诈的数据是少数,多数情况是正常的,所以需要简单的查看数据分布是不是这种情况
- amount 与其他特征列值差异过大需要进行特征缩放
- time字段与交易本身是否为诈骗无关,所以舍弃
- 样本中正常样本也就是class为0的几乎全是有284315,而异常样本class为1 的只有400多个,样本极不平衡。
4 数据规范化
4.1 amount特征缩放并去除time字段
df['Amount'].shape
df = df.drop(columns=['Time','Amount'],axis=1)
df.head()
4.2 解决样本不均衡问题
下采样:
让0和1样本一样少再重新组合成样本数据
过采样:
对1样本进行生成使其和0样本一样多
分别使用下采样和过采样的方式建立和验证模型
5 下采样
划分数据集为特征值和标签值
X = df.iloc[:, df.columns != 'Class']
y = df.iloc[:, df.columns == 'Class']
进行下采样操作
## 得到正常样本索引,即class==0
normal_indices = df[df['Class']==0].index
## 得到异常样本的索引,即class==1,以及异常样本数量
number_records_fraund = len(df[df['Class']!=0])
fraud_indices = np.array(df[df['Class']==1].index)
## 在正常样本中随机采样出指定数量的样本即从class为0的索引中随机选取数量为number_records_fraud大小的样本量,并获取其索引
random_normal_indices = np.random.choice(normal_indices,size = number_records_fraund,replace=False)
random_normal_indices = np.array(random_normal_indices)
##合并索引值
under_sample_indices = np.concatenate([random_normal_indices,fraud_indices])
##选取指定索引的数据
df2 = df.iloc[under_sample_indices,:]
## 查看各样本的所占比例
print('Percent of Fraud:',len(df2[df2['Class']==1])/len(df2))
print('Percent of Normal:',len(df2[df2['Class']==0])/len(df2))
print('Size of Samples:',len(df2))
重新划分特征值与标签值¶
##重新划分特征与标签
X_undersample = df2.ix[:,df2.columns!='Class']
Y_undersample= df2.ix[:,df2.columns=='Class']
5.1 将数据集划分为训练集合测试集
对原始数据进行划分
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=0)
print('原始数据训练集数量:',len(X_train))
print('原始数据测试集数量:',len(X_test))
print('原始数据集总量:',len(X))
对筛选后的样本数据进行划分
X_undersample_train,X_undersample_test,y_undersample_train,y_undersample_test = train_test_split(X_undersample,Y_undersample,test_size=0.3,random_state=0)
##其中random_state,保证了之后的随机选取的模式
print('下采样后数据训练集数量:',len(X_undersample_train))
print('下采样后数据测试集数量:',len(X_undersample_test))
6 模型建立
- 在逻辑回归模型中涉及的参数比较少,使用k折交叉验证对正则化惩罚力度进行调参实验
- 根据目标来指定衡量标准,首先因为样本本身很不均衡,并且识别信用卡欺诈重点识别异常数据,所以使用召回率recall来评估模型
- 逻辑回归中阈值的定对召回率的影响很大,遍历不同的阈值,并通过混淆矩阵可视化结果,选取最优阈值
6.1 对正则化惩罚力度进行调参实验
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold,cross_val_score
from sklearn.metrics import recall_score,confusion_matrix,classification_report
def printing_Kfold_scores(x_train_data,y_train_data):
fold = KFold(5,shuffle=False)
## 定义不同力度的正则化惩罚力度
c_param_range = [0.01,0.1,1,10,100]
## 展示结果用的表格
results_table = pd.DataFrame(index = range(len(c_param_range),2),columns=['C_parameter','Mean recall score'])
results_table['C_parameter'] = c_param_range
## K-fold 表示k 折交叉验证,这里会得到两个索引集合:训练集 = indices[0],测试集= indices[]1
j = 0
#遍历不同的参数
for c_param in c_param_range:
print('-----------------------------------')
print('正则化惩罚力度:',c_param)
print('-----------------------------------')
print('')
recall_accs=[]# 返回不同参数下的模型召回率
for iteration,indices in enumerate(fold.split(x_train_data),start=1):##emurate 同时变量可迭代对象的索引和元素
# 指定算法模型,并给定参数,正则惩罚力度C 以及模式L1,solver='liblinear',liblinear同时支持L1和L2
lr = LogisticRegression(C=c_param,penalty='l1',solver='liblinear')
# print(iteration,indices)
# indices 是元组形式
# 训练模型,注意索引训练时训练集应该是【0】
lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())
# 建立好模型后,预测模型结果,这里使用验证集,索引为indices[1]
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)
## 将每次的评估结果保存,进行k次迭代后计算平均值
recall_accs.append(recall_acc)
print('Iteration',iteration,': 召回率 = ',recall_acc )
#执行问k次后求平均召回率
results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
j +=1
print('')
print('平均召回率',np.mean(recall_accs))
print('')
##找到最好的参数,哪一个recall最高
best_c = results_table.loc[results_table['Mean recall score'].astype('float').idxmax()]['C_parameter']
## 打印虽好的结果
print('**********************************************************')
print('效果最好的模型所选参数 = ',best_c)
print(results_table)
return best_c
# 将模型应用到之前已经分隔好的进行过下采样的样本中
best_c = printing_Kfold_scores(X_undersample_train,y_undersample_train)
6.2 混淆矩阵展示预测结果
混淆矩阵用到的指标值TP,FP,FN,TN
#定义混淆矩阵的画法
def plot_confusion_matrix(cm,
classes,
title='Confusion matrix',
cmap= plt.cm.Blues):
#绘制混淆矩阵
plt.imshow(cm,interpolation='nearest',cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks,classes,rotation=0)
plt.yticks(tick_marks,classes)
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]),range(cm.shape[1])):
plt.text(j,i,cm[i,j],
horizontalalignment = 'center',
color = 'white' if cm[i,j]>thresh else'black')
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
## 传入实际参数
import itertools
lr = LogisticRegression(C = best_c, penalty = 'l1', solver='liblinear')
## 使用训练集拟合
lr.fit(X_undersample_train,y_undersample_train)
## 使用测试集进行预测
y_pred_undersample= lr.predict(X_undersample_test)
# 计算所需值
cnf_matrix = confusion_matrix(y_undersample_test,y_pred_undersample)
np.set_printoptions(precision=2)
print("召回率:",cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
print('精确率:',cnf_matrix[0,0]/(cnf_matrix[0,0]+cnf_matrix[0,1]))
## 绘制混淆矩阵图
class_name=[0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes=class_name)
plt.show()
用下采样的数据集进行建模,并且测试集也是下采样的测试集,在这份测试集中,异常样本和正常样本的比例基本均衡,因为已经对数据集进行过处理。但是实际的数据集并不是这样的,相当于在测试时用理想情况来代替真实情况,这样的检测效果可能会偏高,所以,值得注意的是,在测试的时候,需要使用原始数据的测试集,才能最具代表性,只需要改变传入的测试数据即可,代码如下:
## 传入实际参数
import itertools
lr = LogisticRegression(C = best_c, penalty = 'l1', solver='liblinear')
lr.fit(X_undersample_train,y_undersample_train)
y_pred_undersample= lr.predict(X_test)
# 计算所需值
cnf_matrix = confusion_matrix(y_test,y_pred_undersample)
np.set_printoptions(precision=2)
print("召回率:",cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))# TN/(TN+FN)
print('精确率:',cnf_matrix[0,0]/(cnf_matrix[0,0]+cnf_matrix[0,1]))
## 绘制混淆矩阵图
class_name=[0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes=class_name)
plt.show()
有将近2600多个个样本被误杀,这意味着在实际的业务中,有将近2600多个客户被误认为异常,从而可能被冻结账号、电话询问等
在测试中还需综合考虑,不仅要看模型具体的指标值(例如召回率、精度等),还需要从实际问题角度评估模型到底可不可取。
7 学长的建议
- 在开始任务之前一定对数据的分布情况进行查看,像遇到这种样本极度不平衡的情况要提前了解和处理
- 数据预处理,好的数据是一切任务的基础,像amount这种与其他数据量纲完全不一样的情况且差异比较大要进行特征缩放
- 根据任务选择模型评估指标,因为信用卡异常属于小概率事件,所以模型应做到准确判断异常事件,同时又不误杀即既不错漏又不误杀,所以使用召回率recall和精确度presicion进行衡量,当然也可以使用F1。在其他类似任务中也如是如空难预测、恐怖分子、疾病的识别等等
- 在建模过程中调整参数是非常重要的一步,比如调整正则惩罚力度,这时候交叉检验就必不可少
- 预测结果要与实际任务相结合
- 在信用卡或者说金融相关方面的问题中,也有其他的分类问题如判别是否要放贷或者批额度等等之类的问题,这时候也需要知道各特征重要性,知道哪一个是最重要的,哪一个次重要?哪一个不重要?这样可以对信控工作做出调整
8 最后-毕设帮助
**毕设帮助, 选题指导, 项目分享: ** https://gitee.com/yaa-dc/warehouse-1/blob/master/python/README.md