CategoryResourceRepost/极客时间专栏/数据分析实战45讲/第三模块:数据分析实战篇/40丨数据挖掘实战(2):信用卡诈骗分析.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

292 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="40丨数据挖掘实战2信用卡诈骗分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8c/28/8c087cde91c03ca9bb6d1f23d7b65a28.mp3"></audio>
上一篇文章中我们用随机森林以及之前讲过的SVM、决策树和KNN分类器对信用卡违约数据进行了分析这节课我们来研究下信用卡欺诈。
相比于信用卡违约的比例,信用卡欺诈的比例更小,但是危害极大。如何通过以往的交易数据分析出每笔交易是否正常,是否存在盗刷风险是我们这次项目的目标。
通过今天的学习,你需要掌握以下几个方面:
<li>
了解逻辑回归分类以及如何在sklearn中使用它
</li>
<li>
信用卡欺诈属于二分类问题,欺诈交易在所有交易中的比例很小,对于这种数据不平衡的情况,到底采用什么样的模型评估标准会更准确;
</li>
<li>
完成信用卡欺诈分析的实战项目,并通过数据可视化对数据探索和模型结果评估进一步加强了解。
</li>
## 构建逻辑回归分类器
逻辑回归虽然不在我们讲解的十大经典数据挖掘算法里面,但也是常用的数据挖掘算法。
逻辑回归也叫作logistic回归。虽然名字中带有“回归”但它实际上是分类方法主要解决的是二分类问题当然它也可以解决多分类问题只是二分类更常见一些。
在逻辑回归中使用了Logistic函数也称为Sigmoid函数。Sigmoid函数是在深度学习中经常用到的函数之一函数公式为
<img src="https://static001.geekbang.org/resource/image/3e/18/3e7c7cb4d26d1a71f958610f26d20818.png" alt=""><br>
函数的图形如下所示类似S状
<img src="https://static001.geekbang.org/resource/image/b7/3b/b7a5d39d91fda02b21669137a489743b.png" alt=""><br>
你能看出g(z)的结果在0-1之间当z越大的时候g(z)越大当z趋近于无穷大的时候g(z)趋近于1。同样当z趋近于无穷小的时候g(z)趋近于0。同时函数值以0.5为中心。
为什么逻辑回归算法是基于Sigmoid函数实现的呢你可以这样理解我们要实现一个二分类任务0即为不发生1即为发生。我们给定一些历史数据X和y。其中X代表样本的n个特征y代表正例和负例也就是0或1的取值。通过历史样本的学习我们可以得到一个模型当给定新的X的时候可以预测出y。这里我们得到的y是一个预测的概率通常不是0%和100%而是中间的取值那么我们就可以认为概率大于50%的时候即为发生正例概率小于50%的时候,即为不发生(负例)。这样就完成了二分类的预测。
逻辑回归模型的求解这里不做介绍我们来看下如何使用sklearn中的逻辑回归工具。在sklearn中我们使用LogisticRegression()函数构建逻辑回归分类器,函数里有一些常用的构造参数:
<li>
penalty惩罚项取值为l1或l2默认为l2。当模型参数满足高斯分布的时候使用l2当模型参数满足拉普拉斯分布的时候使用l1
</li>
<li>
solver代表的是逻辑回归损失函数的优化方法。有5个参数可选分别为liblinear、lbfgs、newton-cg、sag和saga。默认为liblinear适用于数据量小的数据集当数据量大的时候可以选用sag或saga方法。
</li>
<li>
max_iter算法收敛的最大迭代次数默认为10。
</li>
<li>
n_jobs拟合和预测的时候CPU的核数默认是1也可以是整数如果是-1则代表CPU的核数。
</li>
当我们创建好之后就可以使用fit函数拟合使用predict函数预测。
## 模型评估指标
我们之前对模型做评估时,通常采用的是准确率(accuracy),它指的是分类器正确分类的样本数与总体样本数之间的比例。这个指标对大部分的分类情况是有效的,不过当分类结果严重不平衡的时候,准确率很难反应模型的好坏。
举个例子对于机场安检中恐怖分子的判断就不能采用准确率对模型进行评估。我们知道恐怖分子的比例是极低的因此当我们用准确率做判断时如果准确率高达99.999%,就说明这个模型一定好么?
其实正因为现实生活中恐怖分子的比例极低,就算我们不能识别出一个恐怖分子,也会得到非常高的准确率。因为准确率的评判标准是正确分类的样本个数与总样本数之间的比例。因此非恐怖分子的比例会很高,就算我们识别不出来恐怖分子,正确分类的个数占总样本的比例也会很高,也就是准确率高。
实际上我们应该更关注恐怖分子的识别这里先介绍下数据预测的四种情况TP、FP、TN、FN。我们用第二个字母P或N代表预测为正例还是负例P为正N为负。第一个字母T或F代表的是预测结果是否正确T为正确F为错误。
所以四种情况分别为:
<li>
TP预测为正判断正确
</li>
<li>
FP预测为正判断错误
</li>
<li>
TN预测为负判断正确
</li>
<li>
FN预测为负判断错误。
</li>
我们知道样本总数=TP+FP+TN+FN预测正确的样本数为TP+TN因此准确率Accuracy = (TP+TN)/(TP+TN+FN+FP)。
实际上,对于分类不平衡的情况,有两个指标非常重要,它们分别是精确度和召回率。
精确率 P = TP/ (TP+FP),对应上面恐怖分子这个例子,在所有判断为恐怖分子的人数中,真正是恐怖分子的比例。
召回率 R = TP/ (TP+FN),也称为查全率。代表的是恐怖分子被正确识别出来的个数与恐怖分子总数的比例。
为什么要统计召回率和精确率这两个指标呢假设我们只统计召回率当召回率等于100%的时候,模型是否真的好呢?
举个例子假设我们把机场所有的人都认为是恐怖分子恐怖分子都会被正确识别这个数字与恐怖分子的总数比例等于100%,但是这个结果是没有意义的。如果我们认为机场里所有人都是恐怖分子的话,那么非恐怖分子(极高比例)都会认为是恐怖分子,误判率太高了,所以我们还需要统计精确率作为召回率的补充。
实际上有一个指标综合了精确率和召回率可以更好地评估模型的好坏。这个指标叫做F1用公式表示为
<img src="https://static001.geekbang.org/resource/image/b1/ce/b122244eae9a74eded619d14c0bc12ce.png" alt=""><br>
F1作为精确率P和召回率R的调和平均数值越大代表模型的结果越好。
## 对信用卡违约率进行分析
我们来看一个信用卡欺诈分析的项目这个数据集你可以从百度网盘因为数据集大于100M所以采用了网盘中下载
>
链接:[https://pan.baidu.com/s/14F8WuX0ZJntdB_r1EC08HA](https://pan.baidu.com/s/14F8WuX0ZJntdB_r1EC08HA) 提取码58gp
数据集包括了2013年9月份两天时间内的信用卡交易数据284807笔交易中一共有492笔是欺诈行为。输入数据一共包括了28个特征V1V2……V28对应的取值以及交易时间Time和交易金额Amount。为了保护数据隐私我们不知道V1到V28这些特征代表的具体含义只知道这28个特征值是通过PCA变换得到的结果。另外字段Class代表该笔交易的分类Class=0为正常非欺诈Class=1代表欺诈。
我们的目标是针对这个数据集构建一个信用卡欺诈分析的分类器采用的是逻辑回归。从数据中你能看到欺诈行为只占到了492/284807=0.172%数据分类结果的分布是非常不平衡的因此我们不能使用准确率评估模型的好坏而是需要统计F1值综合精确率和召回率。我们先梳理下整个项目的流程
<img src="https://static001.geekbang.org/resource/image/92/a5/929c96584cbc25972f63ef39101c96a5.jpg" alt="">
<li>
加载数据;
</li>
<li>
准备阶段我们需要探索数据用数据可视化的方式查看分类结果的情况以及随着时间的变化欺诈交易和正常交易的分布情况。上面已经提到过V1-V28的特征值都经过PCA的变换但是其余的两个字段Time和Amount还需要进行规范化。Time字段和交易本身是否为欺诈交易无关因此我们不作为特征选择只需要对Amount做数据规范化就行了。同时数据集没有专门的测试集使用train_test_split对数据集进行划分
</li>
<li>
分类阶段我们需要创建逻辑回归分类器然后传入训练集数据进行训练并传入测试集预测结果将预测结果与测试集的结果进行比对。这里的模型评估指标用到了精确率、召回率和F1值。同时我们将精确率-召回率进行了可视化呈现。
</li>
基于上面的流程,具体代码如下:
```
# -*- coding:utf-8 -*-
# 使用逻辑回归对信用卡欺诈进行分类
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import itertools
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, precision_recall_curve
from sklearn.preprocessing import StandardScaler
import warnings
warnings.filterwarnings('ignore')
# 混淆矩阵可视化
def plot_confusion_matrix(cm, classes, normalize = False, title = 'Confusion matrix&quot;', cmap = plt.cm.Blues) :
plt.figure()
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] &gt; thresh else 'black')
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()
# 显示模型评估结果
def show_metrics():
tp = cm[1,1]
fn = cm[1,0]
fp = cm[0,1]
tn = cm[0,0]
print('精确率: {:.3f}'.format(tp/(tp+fp)))
print('召回率: {:.3f}'.format(tp/(tp+fn)))
print('F1值: {:.3f}'.format(2*(((tp/(tp+fp))*(tp/(tp+fn)))/((tp/(tp+fp))+(tp/(tp+fn))))))
# 绘制精确率-召回率曲线
def plot_precision_recall():
plt.step(recall, precision, color = 'b', alpha = 0.2, where = 'post')
plt.fill_between(recall, precision, step ='post', alpha = 0.2, color = 'b')
plt.plot(recall, precision, linewidth=2)
plt.xlim([0.0,1])
plt.ylim([0.0,1.05])
plt.xlabel('召回率')
plt.ylabel('精确率')
plt.title('精确率-召回率 曲线')
plt.show();
# 数据加载
data = pd.read_csv('./creditcard.csv')
# 数据探索
print(data.describe())
# 设置plt正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘制类别分布
plt.figure()
ax = sns.countplot(x = 'Class', data = data)
plt.title('类别分布')
plt.show()
# 显示交易笔数,欺诈交易笔数
num = len(data)
num_fraud = len(data[data['Class']==1])
print('总交易笔数: ', num)
print('诈骗交易笔数:', num_fraud)
print('诈骗交易比例:{:.6f}'.format(num_fraud/num))
# 欺诈和正常交易可视化
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(15,8))
bins = 50
ax1.hist(data.Time[data.Class == 1], bins = bins, color = 'deeppink')
ax1.set_title('诈骗交易')
ax2.hist(data.Time[data.Class == 0], bins = bins, color = 'deepskyblue')
ax2.set_title('正常交易')
plt.xlabel('时间')
plt.ylabel('交易次数')
plt.show()
# 对Amount进行数据规范化
data['Amount_Norm'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1,1))
# 特征选择
y = np.array(data.Class.tolist())
data = data.drop(['Time','Amount','Class'],axis=1)
X = np.array(data.as_matrix())
# 准备训练集和测试集
train_x, test_x, train_y, test_y = train_test_split (X, y, test_size = 0.1, random_state = 33)
# 逻辑回归分类
clf = LogisticRegression()
clf.fit(train_x, train_y)
predict_y = clf.predict(test_x)
# 预测样本的置信分数
score_y = clf.decision_function(test_x)
# 计算混淆矩阵,并显示
cm = confusion_matrix(test_y, predict_y)
class_names = [0,1]
# 显示混淆矩阵
plot_confusion_matrix(cm, classes = class_names, title = '逻辑回归 混淆矩阵')
# 显示模型评估分数
show_metrics()
# 计算精确率,召回率,阈值用于可视化
precision, recall, thresholds = precision_recall_curve(test_y, score_y)
plot_precision_recall()
```
运行结果:
```
Time V1 ... Amount Class
count 284807.000000 2.848070e+05 ... 284807.000000 284807.000000
mean 94813.859575 1.165980e-15 ... 88.349619 0.001727
std 47488.145955 1.958696e+00 ... 250.120109 0.041527
min 0.000000 -5.640751e+01 ... 0.000000 0.000000
25% 54201.500000 -9.203734e-01 ... 5.600000 0.000000
50% 84692.000000 1.810880e-02 ... 22.000000 0.000000
75% 139320.500000 1.315642e+00 ... 77.165000 0.000000
max 172792.000000 2.454930e+00 ... 25691.160000 1.000000
[8 rows x 31 columns]
```
<img src="https://static001.geekbang.org/resource/image/5e/61/5e98974d6c2e87168b40e5f751d00f61.png" alt="">
```
总交易笔数: 284807
诈骗交易笔数: 492
诈骗交易比例0.001727
```
<img src="https://static001.geekbang.org/resource/image/c8/d2/c8a59cb4f3d94c91eb6648be1b0429d2.png" alt="">
<img src="https://static001.geekbang.org/resource/image/bf/39/bfe65c34b74de661477d9b59d4db6a39.png" alt="">
```
精确率: 0.841
召回率: 0.617
F1值: 0.712
```
<img src="https://static001.geekbang.org/resource/image/28/69/28ccd0f8d609046b2bafb27fb1195269.png" alt=""><br>
你能看出来欺诈交易的笔数为492笔占所有交易的比例是很低的即0.001727,我们可以通过数据可视化的方式对欺诈交易和正常交易的分布进行呈现。另外通过可视化,我们也能看出精确率和召回率之间的关系,当精确率高的时候,召回率往往很低,召回率高的时候,精确率会比较低。
代码有一些模块需要说明下。
我定义了plot_confusion_matrix函数对混淆矩阵进行可视化。什么是混淆矩阵呢混淆矩阵也叫误差矩阵实际上它就是TP、FP、TN、FN这四个数值的矩阵表示帮助我们判断预测值和实际值相比对了多少。从这个例子中你能看出TP=37FP=7FN=23。所以精确率P=TP/(TP+FP)=37/(37+7)=0.841召回率R=TP/(TP+FN)=37/(37+23)=0.617。
然后使用了sklearn中的precision_recall_curve函数通过预测值和真实值来计算精确率-召回率曲线。precision_recall_curve函数会计算在不同概率阈值情况下的精确率和召回率。最后定义plot_precision_recall函数绘制曲线。
## 总结
今天我给你讲了逻辑回归的概念和相关工具的使用另外学习了在数据样本不平衡的情况下如何评估模型。这里你需要了解精确率召回率和F1的概念和计算方式。最后在信用卡欺诈分析的项目中我们使用了逻辑回归工具并对混淆矩阵进行了计算同时在模型结果评估中使用了精确率、召回率和F1值最后得到精确率-召回率曲线的可视化结果。
从这个项目中你能看出来,不是所有的分类都是样本平衡的情况,针对正例比例极低的情况,比如信用卡欺诈、某些疾病的识别,或者是恐怖分子的判断等,都需要采用精确率-召回率来进行统计。
<img src="https://static001.geekbang.org/resource/image/ab/50/abee1a58b99814f1e0218778b98a6950.png" alt=""><br>
最后留两道思考题吧今天我们对信用卡欺诈数据集进行了分析它是一个不平衡数据集你知道还有哪些数据属于不平衡数据么另外请你使用线性SVM对应sklearn中的LinearSVC对信用卡欺诈数据集进行分类并计算精确率、召回率和F1值。
欢迎你在评论区与我分享你的答案,也欢迎点击“请朋友读”,把这篇文章分享给你的朋友或者同事。