社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python分析信用卡反欺诈(上)——逻辑回归、随机森林、SVM三种方法建模比较

一个普普通通简简单单平平凡凡的神 • 8 年前 • 527 次点击  

前言

  • 本文研究的是大数据量(284807条数据)下模型选择的问题,也参考了一些文献,但大多不够清洗,因此吐血整理本文,希望对大家有帮助;
  • 本文试着从数据分析师的角度,设想“拿到数据该如何寻找规律、选那种模型来构建反欺诈模型?”的角度来分析,以业务导向为主,不深究算法原理;
  • 后面会有一篇文章(python分析信用卡反欺诈(下)),来说明数据结构极度不平衡的情况下,该如何修正数据集、如何调整参数;
  • 阅读本文大约需要15分钟,如有错误欢迎留言指正,谢谢😄😄

一,数据来源及项目概况

数据是从kaggle上看到的项目,具体链接如下:

Credit Card Fraud Detection

获取本例数据的,可在上述项目详情链接中下载数据。

数据集包含欧洲持卡人于2013年9月通过信用卡进行的交易。该数据集提供两天内发生的交易,其中在284,807笔交易中有492起欺诈行为。数据集非常不平衡,负面类别(欺诈)占所有交易的0.172%。

它只包含数值输入变量,这是PCA变换的结果。不幸的是,由于保密问题,我们无法提供有关数据的原始特征和更多背景信息。特征V1,V2,... V28是用PCA获得的主要组件,唯一没有用PCA转换的特征是'Time'和'Amount'。

  • “时间”包含每个事务与数据集中第一个事务之间经过的秒数。
  • '金额'是交易金额,该特征可以用于依赖于例子的成本敏感性学习。
  • “Class”是响应变量,在欺诈的情况下其值为1,否则为0。

二,准备并初步查看数据集

# 导入包
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代表欺诈,二者数量严重失衡,极度不平衡,根本不在一个数量级上;

三,欺诈与时间序列分布关系

# 查看二者的描述性统计,与时间的序列分布关系
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()
  • 欺诈与时间并没有必然联系,不存在周期性;
  • 正常交易有明显的周期性,有类似双峰这样的趋势。

四,欺诈与金额Amount的关系和分布情况

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()
  • 金额普遍较低,可见金额这一列的数据对分析的参考价值不大。

五,查看各个自变量(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()

六,三种方法建模并分析

本部分将应用逻辑回归、随机森林、支持向量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

小结

  • 通过三种模型的表现可知,随机森林的误杀率最低;
  • 不应只盯着精度,有时候模型的精度高并不能说明模型就好,特别是像本项目中这样的数据严重不平衡的。举个例子,我们拿到有1000条病人的数据集,其中990人为健康,10个有癌症,我们要通过建模找出这10个癌症病人,如果一个模型预测到了全部健康的990人,而10个病人一个都没找到,此时其正确率仍然有99%,但这个模型是无用的,并没有达到我们寻找病人的目的;
  • 建模分析时,遇到像本例这样的极度不平衡数据集,因采取下采样、过采样等办法,使数据平衡,这样的预测才有意义,下一篇文章将针对这个问题进行改进。
  • 模型、算法并没有高低、好坏之分,只是在不同的情况下有不同的发挥罢了,这点应正确的看待。

以上就是本文的全部,谢谢你查看本文,后面还有一篇“python分析信用卡反欺诈(下)”。

(人气稀薄😫😫,急需关爱😄😄。如果您竟然看到了这里还没走开,请帮忙多多点赞、收藏哈,谢谢啦朋友们~~)


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/LMqLG0lHAU
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/11648