Python分析信用卡反欺诈!骗我程序员,不存在的!
前言:
本文研究的是大数据量(284807条数据)下模型选择的问题,也参考了一些文献,但大多不够清晰,因此吐血整理本文,希望对大家有帮助;
本文试着从数据分析师的角度,设想“拿到数据该如何寻找规律、选哪种模型来构建反欺诈模型?”的角度来分析,以业务导向为主,不深究算法原理;
下一篇文章会说明数据结构极度不平衡的情况下,该如何修正数据集、如何调整参数。
数据来源及项目概况
数据是从kaggle上看到的项目,具体链接如下:
https://www.kaggle.com/mlg-ulb/creditcardfraud
获取本例数据的,可在上述项目详情链接中下载数据。
数据集包含欧洲持卡人于2013年9月通过信用卡进行的交易。该数据集提供两天内发生的交易,其中在284,807笔交易中有492起欺诈行为。
数据集非常不平衡,负面类别(欺诈)占所有交易的0.172%。
它只包含数值输入变量,这是PCA变换的结果。不幸的是,由于保密问题,我们无法提供有关数据的原始特征和更多背景信息。特征V1,V2,... V28是用PCA获得的主要组件,唯一没有用PCA转换的特征是'Time'和'Amount'。
-
“时间”包含每个事务与数据集中第一个事务之间经过的秒数。
-
'金额'是交易金额,该特征可以用于依赖于例子的成本敏感性学习。
-
“Class”是响应变量,在欺诈的情况下其值为1,否则为0。
2、准备并初步查看数据集
-
# 导入包
-
import numpy as np
-
import pandas as pd
-
import matplotlib.pyplot as plt
-
import matplotlib.gridspec as gridspec
-
import seaborn as sns; plt.style.use('ggplot')
-
import sklearn
-
from sklearn.preprocessing import StandardScaler
-
from sklearn.model_selection import train_test_split
-
from sklearn.utils import shuffle
-
from sklearn.metrics import confusion_matrix
-
from sklearn.manifold import TSNE
-
pass
-
# 倒入并查看数据
-
crecreditcard_data=pd.read_csv('./creditcard.csv')
-
crecreditcard_data.shape,crecreditcard_data.info()
-
<class 'pandas.core.frame.DataFrame'>
-
RangeIndex: 284807 entries, 0 to 284806
-
Data columns (total 31 columns):
-
Time 284807 non-null float64
-
V1 284807 non-null float64
-
V2 284807 non-null float64
-
V3 284807 non-null float64
-
V4 284807 non-null float64
-
V5 284807 non-null float64
-
V6 284807 non-null float64
-
V7 284807 non-null float64
-
V8 284807 non-null float64
-
V9 284807 non-null float64
-
V10 284807 non-null float64
-
V11 284807 non-null float64
-
V12 284807 non-null float64
-
V13 284807 non-null float64
-
V14 284807 non-null float64
-
V15 284807 non-null float64
-
V16 284807 non-null float64
-
V17 284807 non-null float64
-
V18 284807 non-null float64
-
V19 284807 non-null float64
-
V20 284807 non-null float64
-
V21 284807 non-null float64
-
V22 284807 non-null float64
-
V23 284807 non-null float64
-
V24 284807 non-null float64
-
V25 284807 non-null float64
-
V26 284807 non-null float64
-
V27 284807 non-null float64
-
V28 284807 non-null float64
-
Amount 284807 non-null float64
-
Class 284807 non-null int64
-
dtypes: float64(30), int64(1)
-
memory usage: 67.4 MB
-
((284807, 31), None)
-
crecreditcard_data.describe()
-
pass
-
crecreditcard_data.head()
-
pass
-
# 看看欺诈与非欺诈的比例如何
-
count_classes=pd.value_counts(crecreditcard_data['Class'],sort=True).sort_index()
-
# 统计下具体数据
-
count_classes.value_counts()
-
# 也可以用count_classes[0],count_classes[1]看分别数据
-
284315 1
-
492 1
-
Name: Class, dtype: int64
-
count_classes.plot(kind='bar')
-
plt.show()

0代表正常,1代表欺诈,二者数量严重失衡,极度不平衡,根本不在一个数量级上。
3、欺诈与时间序列分布关系
-
# 查看二者的描述性统计,与时间的序列分布关系
-
print('Normal')
-
print(crecreditcard_data.
-
Time[crecreditcard_data.Class == 0].describe())
-
print('-'*25)
-
print('Fraud')
-
print(crecreditcard_data.
-
Time[crecreditcard_data.Class == 1].describe())
-
Normal
-
count 284315.000000
-
mean 94838.202258
-
std 47484.015786
-
min 0.000000
-
25% 54230.000000
-
50% 84711.000000
-
75% 139333.000000
-
max 172792.000000
-
Name: Time, dtype: float64
-
-
Fraud
-
count 492.000000
-
mean 80746.806911
-
std 47835.365138
-
min 406.000000
-
25% 41241.500000
-
50% 75568.500000
-
75% 128483.000000
-
max 170348.000000
-
Name: Time, dtype: float64
-
f,(ax1,ax2)=plt.subplots(2,1,sharex=True,figsize=(12,6))
-
bins=50
-
ax1.hist(crecreditcard_data.Time[crecreditcard_data.Class == 1],bins=bins)
-
ax1.set_title('欺诈(Fraud))',fontsize=22)
-
ax1.set_ylabel('交易量',fontsize=15)
-
ax2.hist(crecreditcard_data.Time[crecreditcard_data.Class == 0],bins=bins)
-
ax2.set_title('正常(Normal',fontsize=22)
-
plt.xlabel('时间(单位:秒)',fontsize=15)
-
plt.xticks(fontsize=15)
-
plt.ylabel('交易量',fontsize=15)
-
# plt.yticks(fontsize=22)
-
plt.show()

欺诈与时间并没有必然联系,不存在周期性;
正常交易有明显的周期性,有类似双峰这样的趋势。
4、欺诈与金额的关系和分布情况
-
print('欺诈')
-
print(crecreditcard_data.Amount[crecreditcard_data.Class ==1].describe())
-
print('-'*25)
-
print('正常交易')
-
print(crecreditcard_data.Amount[crecreditcard_data.Class==0].describe())
-
欺诈
-
count 492.000000
-
mean 122.211321
-
std 256.683288
-
min 0.000000
-
25% 1.000000
-
50% 9.250000
-
75% 105.890000
-
max 2125.870000
-
Name: Amount, dtype: float64
-
-
正常交易
-
count 284315.000000
-
mean 88.291022
-
std 250.105092
-
min 0.000000
-
25% 5.650000
-
50% 22.000000
-
75% 77.050000
-
max 25691.160000
-
Name: Amount, dtype: float64
-
f,(ax1,ax2)=plt.subplots(2,1,sharex=True,figsize=(12,6))
-
bins=30
-
ax1.hist(crecreditcard_data.Amount[crecreditcard_data.Class == 1],bins=bins)
-
ax1.set_title('欺诈(Fraud)',fontsize=22)
-
ax1.set_ylabel('交易量',fontsize=15)
-
ax2.hist(crecreditcard_data.Amount[crecreditcard_data.Class == 0],bins=bins)
-
ax2.set_title('正常(Normal)',fontsize=22)
-
plt.xlabel('金额($)',fontsize=15)
-
plt.xticks(fontsize=15)
-
plt.ylabel('交易量',fontsize=15)
-
plt.yscale('log')
-
plt.show()

金额普遍较低,可见金额这一列的数据对分析的参考价值不大。
5、查看各个自变量(V1-V29)与因变量的关系
看看各个变量与正常、欺诈之间是否存在联系,为了更直观展示,通过distplot图来逐个判断,如下:
-
features=[x for x in crecreditcard_data.columns
-
if x not in ['Time','Amount','Class']]
-
plt.figure(figsize=(12,28*4))
-
gs =gridspec.GridSpec(28,1)
-
import warnings
-
warnings.filterwarnings('ignore')
-
for i,cn in enumerate(crecreditcard_data[v_features]):
-
ax=plt.subplot(gs[i])
-
sns.distplot(crecreditcard_data[cn][crecreditcard_data.Class==1],bins=50,color='red')
-
sns.distplot(crecreditcard_data[cn][crecreditcard_data.Class==0],bins=50,color='green')
-
ax.set_xlabel('')
-
ax.set_title('直方图:'+str(cn))
-
plt.savefig('各个变量与class的关系.png',transparent=False,bbox_inches='tight')
-
plt.show()

红色表示欺诈,绿色表示正常。
-
两个分布的交叉面积越大,欺诈与正常的区分度最小,如V15;
-
两个分布的交叉面积越小,则该变量对因变量的影响越大,如V14。
下面我们看看各个单变量与class的相关性分析,为更直观展示,直接作图,如下:
-
# 各个变量的矩阵分布
-
crecreditcard_data.hist(figsize=(15,15),bins=50)
-
plt.show()
6、三种方法建模并分析
本部分将应用逻辑回归、随机森林、支持向量SVM三种方法建模分析,分别展开如下:
准备数据:
-
# 先把数据分为欺诈组和正常组,然后按比例生产训练和测试数据集
-
# 分组
-
Fraud=crecreditcard_data[crecreditcard_data.Class == 1]
-
Normal=crecreditcard_data[crecreditcard_data.Class == 0]
-
# 训练特征集
-
x_train=Fraud.sample(frac=0.7)
-
x_train=pd.concat([x_train,Normal.sample(frac=0.7)],axis=0)
-
# 测试特征集
-
x_test=crecreditcard_data.loc[~crecreditcard_data.index.isin(x_train.index)]
-
# 标签集
-
y_train=x_train.Class
-
y_test=x_test.Class
-
# 去掉特征集里的标签和时间列
-
x_train=x_train.drop(['Class','Time'],axis=1)
-
x_test=x_test.drop(['Class','Time'],axis=1)
-
# 查看数据结构
-
print(x_train.shape,y_train.shape,
-
'\n',x_test.shape,y_test.shape)
-
(199364, 29) (199364,)
-
(85443, 29) (85443,)
6.1 逻辑回归方法
-
from sklearn import metrics
-
import scipy.optimize as op
-
from sklearn.linear_model import LogisticRegression
-
from sklearn.cross_validation import KFold,cross_val_score
-
from sklearn.metrics import (precision_recall_curve,
-
auc,roc_auc_score,
-
roc_curve,recall_score,
-
classification_report)
-
lrmodel = LogisticRegression(penalty='l2')
-
lrmodel.fit(x_train, y_train)
-
#查看模型
-
print('lrmodel')
-
print(lrmodel)
-
lrmodel
-
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
-
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
-
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
-
verbose=0, warm_start=False)
-
#查看混淆矩阵
-
ypred_lr=lrmodel.predict(x_test)
-
print('confusion_matrix')
-
print(metrics.confusion_matrix(y_test,ypred_lr))
-
confusion_matrix
-
[[85284 11]
-
[ 56 92]]
-
#查看分类报告
-
print('classification_report')
-
print(metrics.classification_report(y_test,ypred_lr))
-
classification_report
-
precision recall f1-score support
-
0 1.00 1.00 1.00 85295
-
1 0.89 0.62 0.73 148
-
avg / total 1.00 1.00 1.00 85443
-
#查看预测精度与决策覆盖面
-
print('Accuracy:%f'%(metrics.accuracy_score(y_test,ypred_lr)))
-
print('Area under the curve:%f'%(metrics.roc_auc_score(y_test,ypred_lr)))
-
Accuracy:0.999216
-
Area under the curve:0.810746
6.2 随机森林模型
-
from sklearn.ensemble import RandomForestClassifier
-
rfmodel=RandomForestClassifier()
-
rfmodel.fit(x_train,y_train)
-
#查看模型
-
print('rfmodel')
-
rfmodel
-
rfmodel
-
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
-
max_depth=None, max_features='auto', max_leaf_nodes=None,
-
min_impurity_decrease=0.0, min_impurity_split=None,
-
min_samples_leaf=1, min_samples_split=2,
-
min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
-
oob_score=False, random_state=None, verbose=0,
-
warm_start=False)
-
#查看混淆矩阵
-
ypred_rf=rfmodel.predict(x_test)
-
print('confusion_matrix')
-
print(metrics.confusion_matrix(y_test,ypred_rf))
-
confusion_matrix
-
[[85291 4]
-
[ 34 114]]
-
#查看分类报告
-
print('classification_report')
-
print(metrics.classification_report(y_test,ypred_rf))
-
classification_report
-
precision recall f1-score support
-
0 1.00 1.00 1.00 85295
-
1 0.97 0.77 0.86 148
-
avg / total 1.00 1.00 1.00 85443
-
#查看预测精度与决策覆盖面
-
print('Accuracy:%f'%(metrics.accuracy_score(y_test,ypred_rf)))
-
print('Area under the curve:%f'%(metrics.roc_auc_score(y_test,ypred_rf)))
-
Accuracy:0.999625
-
Area under the curve:0.902009
6.3支持向量机SVM
-
# SVM分类
-
from sklearn.svm import SVC
-
svcmodel=SVC(kernel='sigmoid')
-
svcmodel.fit(x_train,y_train)
-
#查看模型
-
print('svcmodel')
-
svcmodel
-
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
-
decision_function_shape='ovr', degree=3, gamma='auto', kernel='sigmoid',
-
max_iter=-1, probability=False, random_state=None, shrinking=True,
-
tol=0.001, verbose=False)
-
#查看混淆矩阵
-
ypred_svc=svcmodel.predict(x_test)
-
print('confusion_matrix')
-
print(metrics.confusion_matrix(y_test,ypred_svc))
-
confusion_matrix
-
[[85197 98]
-
[ 142 6]]
-
#查看分类报告
-
print('classification_report')
-
print(metrics.classification_report(y_test,ypred_svc))
-
classification_report
-
precision recall f1-score support
-
0 1.00 1.00 1.00 85295
-
1 0.06 0.04 0.05 148
-
avg / total 1.00 1.00 1.00 85443
-
#查看预测精度与决策覆盖面
-
print('Accuracy:%f'%(metrics.accuracy_score(y_test,ypred_svc)))
-
print('Area under the curve:%f'%(metrics.roc_auc_score(y_test,ypred_svc)))
-
Accuracy:0.997191
-
Area under the curve:0.519696
7、小结
-
通过三种模型的表现可知,随机森林的误杀率最低;
-
不应只盯着精度,有时候模型的精度高并不能说明模型就好,特别是像本项目中这样的数据严重不平衡的情况。举个例子,我们拿到有1000条病人的数据集,其中990人为健康,10个有癌症,我们要通过建模找出这10个癌症病人,如果一个模型预测到了全部健康的990人,而10个病人一个都没找到,此时其正确率仍然有99%,但这个模型是无用的,并没有达到我们寻找病人的目的;
-
建模分析时,遇到像本例这样的极度不平衡数据集,因采取下采样、过采样等办法,使数据平衡,这样的预测才有意义,下一篇文章将针对这个问题进行改进;
-
模型、算法并没有高低、好坏之分,只是在不同的情况下有不同的发挥罢了,这点应正确的看待。
文章出自:http://qh.itpxw.cn/peixun/software/201956822.html
文章标题:信用卡诈骗不用怕 程序员利用python分析一招搞定
免责声明:本站文章均由入驻起航学习网的会员所发或者网络转载,所述观点仅代表作者本人,不代表起航学习网立场。如有侵权或者其他问题,请联系举报,必删。侵权投诉
(责任编辑:IT培训网)