常见的数据分析用例 —— 信用卡交易欺诈检测
文章目录
- 引言
- 数据集
- 分析
- 1. 读入数据并快速浏览
- 2.计算欺诈交易占数据集中交易总数的百分比
- 3. 类别不平衡对模型的影响
- 3.1 总体思路
- (1)数据的划分
- (2)训练模型
- (3)测试模型
- (4)解决不平衡问题
- 3.2 为什么要解决不平衡问题
- 4. 处理不平衡数据集
- 5. 训练和评估模型
- 5.1 回到原始数据,制定规则
- 5.1.1 代码
- 5.1.2 结果分析
- 混淆矩阵
- 分类报告
- 结论
- 5.2 逻辑回归模型(未使用SMOTE)和逻辑回归模型(使用SMOTE)
- 代码及结果
- 混淆矩阵
- 分类报告
- 6. 进一步
- 7. 随机森林模型
- 8. 模型应用
- 误报处理
- 漏报处理
引言
数据分析在银行中的应用有如下:
投资风险分析
客户终身价值预测
客户细分
客户流失率预测
个性化营销
客户情绪分析
虚拟助理和聊天机器人
……
这里是一个常见的数据分析用例
欺诈检测是为识别和防止欺诈活动以及财务损失而采取的一种主动措施
一般的做法有:
- 统计学:统计参数计算、回归、概率分布、数据匹配;
- 人工智能:数据挖掘、机器学习、深度学习
机器学习是欺诈检测的重要支柱,其工具包提供了两种方法:
- 监督方法:K-近邻、逻辑回归、支持向量机、决策树、随机森林、时间序列分析、神经网络等。
- 无监督方法:聚类分析、链接分析、自组织地图、主成分分析、异常识别等。
目前没有通用的机器学习算法用于欺诈检测。相反,对于现实世界的数据科学用例,通常会选择几种方法,通过测试比较,选择最佳的。
数据集
Credit Card Fraud Detection | Kaggle数据集:
https://www.kaggle.com/mlg-ulb/creditcardfraud
该数据集是Kaggle信用卡欺诈检测数据集的一个修改样本,持卡人拥有信用卡的交易情况
下载以后保存在Jupyter notebook默认目录下
分析
1. 读入数据并快速浏览
import pandas as pd creditcard_data = pd.read_csv('creditcard.csv', index_col=0) print(creditcard_data.info()) print('\n') pd.options.display.max_columns = len(creditcard_data) print(creditcard_data.head(3))
结果如下:
Index: 284807 entries, 0.0 to 172792.0 Data columns (total 30 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 V1 284807 non-null float64 1 V2 284807 non-null float64 2 V3 284807 non-null float64 3 V4 284807 non-null float64 4 V5 284807 non-null float64 5 V6 284807 non-null float64 6 V7 284807 non-null float64 7 V8 284807 non-null float64 8 V9 284807 non-null float64 9 V10 284807 non-null float64 10 V11 284807 non-null float64 11 V12 284807 non-null float64 12 V13 284807 non-null float64 13 V14 284807 non-null float64 14 V15 284807 non-null float64 15 V16 284807 non-null float64 16 V17 284807 non-null float64 17 V18 284807 non-null float64 18 V19 284807 non-null float64 19 V20 284807 non-null float64 20 V21 284807 non-null float64 21 V22 284807 non-null float64 22 V23 284807 non-null float64 23 V24 284807 non-null float64 24 V25 284807 non-null float64 25 V26 284807 non-null float64 26 V27 284807 non-null float64 27 V28 284807 non-null float64 28 Amount 284807 non-null float64 29 Class 284807 non-null int64 dtypes: float64(29), int64(1) memory usage: 67.4 MB None V1 V2 V3 V4 V5 V6 V7 \ Time 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 0.462388 0.239599 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 -0.082361 -0.078803 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 1.800499 0.791461 V8 V9 V10 V11 V12 V13 V14 \ Time 0.0 0.098698 0.363787 0.090794 -0.551600 -0.617801 -0.991390 -0.311169 0.0 0.085102 -0.255425 -0.166974 1.612727 1.065235 0.489095 -0.143772 1.0 0.247676 -1.514654 0.207643 0.624501 0.066084 0.717293 -0.165946 V15 V16 V17 V18 V19 V20 V21 \ Time 0.0 1.468177 -0.470401 0.207971 0.025791 0.403993 0.251412 -0.018307 0.0 0.635558 0.463917 -0.114805 -0.183361 -0.145783 -0.069083 -0.225775 1.0 2.345865 -2.890083 1.109969 -0.121359 -2.261857 0.524980 0.247998 V22 V23 V24 V25 V26 V27 V28 \ Time 0.0 0.277838 -0.110474 0.066928 0.128539 -0.189115 0.133558 -0.021053 0.0 -0.638672 0.101288 -0.339846 0.167170 0.125895 -0.008983 0.014724 1.0 0.771679 0.909412 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752 Amount Class Time 0.0 149.62 0 0.0 2.69 0 1.0 378.66 0
这个数据集共有284807条记录。
数据集包含30个列,其中29个列是float64类型(浮点数),1个列是int64类型(整数)。
每一列的数据都是非空的(没有缺失值)。
通过creditcard_data.head(3),我们查看数据集的前3行:
Time:表示交易时间。
V1 到 V28:这些是经过PCA(主成分分析)转换后的特征
Amount:表示交易金额。
Class:目标变量,表示交易是否为欺诈(1表示欺诈,0表示正常)。
数据集非常大且没有缺失值,适合进行机器学习模型的训练。
通过初步的浏览,我们对数据有了一个基本的了解,可以进一步进行数据分析和建模工作。
2.计算欺诈交易占数据集中交易总数的百分比
# 计算欺诈交易数量 fraud_count = creditcard_data[creditcard_data['Class'] == 1].shape[0] # 计算总交易数量 total_count = creditcard_data.shape[0] # 计算百分比 fraud_percentage = (fraud_count / total_count) * 100 # 打印结果 print(f'欺诈交易占总交易数的百分比: {fraud_percentage:.2f}%')
结果如下:
使用条件筛选creditcard_data[creditcard_data[‘Class’] == 1]获取所有标记为欺诈交易的数据,然后使用shape[0]计算行数(即欺诈交易的数量)。
欺诈案件总归占少数,隐藏在真实的交易中。
创建一个图表,将欺诈与非欺诈的数据点可视化
import matplotlib.pyplot as plt import numpy as np # prep_data(df)从数据集中提取特征和标签 def prep_data(df): X = df.iloc[:, 1:28] #选择第1列到第28列的数据作为特征 X = np.array(X).astype(float) #将数据框转换为numpy数组,并将数据类型转换为float(浮点数) y = df.iloc[:, 29] #选择第29列的数据作为标签(目标变量)(1表示欺诈,0表示正常) y = np.array(y).astype(float) #标签转换为numpy数组 return X, y def plot_data(X, y): plt.scatter(X[y==0, 0], X[y==0, 1], label='Class #0', alpha=0.5, linewidth=0.15) plt.scatter(X[y==1, 0], X[y==1, 1], label='Class #1', alpha=0.5, linewidth=0.15, c='r') plt.legend() return plt.show() X, y = prep_data(creditcard_data) plot_data(X, y)
结果如下:
欺诈性交易的比例非常低,类别不平衡
3. 类别不平衡对模型的影响
3.1 总体思路
数据集是信用卡交易记录,我们想通过这个数据找出哪些交易是欺诈行为,哪些是正常的交易。
我们希望建立一个聪明的模型,帮助我们准确地识别哪些交易是欺诈行为。
可以分为几个简单的步骤:
(1)数据的划分
首先,我们把数据分成两部分:一部分用于训练模型,另一部分用于测试模型。打个比方,用历年真题来学习,用今年的考试题来测试学习效果。
(2)训练模型
这里我们打算使用“逻辑回归”的数学方法来训练我们的模型。让这个模型会学到哪些交易看起来像是欺诈,哪些交易看起来是正常的。
(3)测试模型
训练好模型后,用测试数据来检查模型的表现。我们会得到一个结果表,显示模型预测的和实际的结果对比。比如,模型认为某些交易是欺诈,但实际上它们不是;或者模型认为某些交易是正常的,但实际上它们是欺诈。
(4)解决不平衡问题
我们的数据里,正常交易很多,欺诈交易很少。为了让模型更好地识别欺诈交易,我们使用了一种叫做SMOTE的方法。这个方法会“制造”一些假的欺诈交易,让数据看起来更平衡,就像我们在班级里增加一些假人,让男女比例更均匀。
也就是说用 SMOTE 来重新平衡数据,它不只是创建观察值的精确副本,而是使用欺诈交易的最近邻居的特征来创建新的、合成的样本,这些样本与少数人类别中的现有观察值相当相似
3.2 为什么要解决不平衡问题
在训练模型时,希望模型能更好地学习到如何识别每一类数据。
如果数据非常不平衡,比如正常交易很多,欺诈交易很少,模型会倾向于只学习正常交易,而忽略了欺诈交易。
打个比方,假设你在班级里玩一个游戏,老师给你看10张卡片,其中9张是苹果,1张是橙子。然后老师让你猜下一张卡片是什么。你很可能会猜是苹果,因为苹果的卡片太多了。如果这个时候老师给你多一些橙子的卡片,比如让你看到5张苹果和5张橙子,那么你在猜下一张卡片时,就会更认真地考虑两种可能性。
对于模型来说也是这样,如果我们的数据里正常交易很多,欺诈交易很少,模型在训练过程中会主要学习到正常交易的特征,而不会很好地学习到欺诈交易的特征。
结果就是模型会更倾向于预测所有的交易都是正常的,
解决方法——让数据平衡:
为了让模型更好地学习到两类交易的特征,我们可以使用一些技术手段,比如SMOTE。这种方法会“制造”一些假的欺诈交易,让数据看起来更平衡。
这样模型在训练过程中会看到更多的欺诈交易,更好地理解每一类数据的特征,从而更准确地识别出欺诈交易
这样,在预测时就会更准确地判断哪些交易是正常的,哪些是欺诈的。
就像你在玩卡片游戏时,看到的苹果和橙子数量差不多,你在猜下一张卡片时就会更准确一样。
4. 处理不平衡数据集
让我们把SMOTE应用于该信用卡数据,提供了更多的少数类别的观察结果
SMOTE首先识别数据集中属于少数类的样本。
对于每个少数类样本,SMOTE会在其最近邻样本中随机选择一个样本。
在这两个样本之间随机插值,生成一个新的合成样本。
通过上述步骤生成足够多的合成样本,使得少数类样本数量与多数类样本数量接近或相等。
from imblearn.over_sampling import SMOTE # 实例化SMOTE对象 method = SMOTE() # 对数据进行过采样 X_resampled, y_resampled = method.fit_resample(X, y) # 可视化过采样后的数据 plot_data(X_resampled, y_resampled) # 打印过采样前后的记录数量 print(f'原始数据集记录数量: {X.shape[0]}') print(f'过采样后数据集记录数量: {X_resampled.shape[0]}') # 打印过采样前后的类别分布 print(f'原始数据集类别分布:\n{pd.Series(y).value_counts()}') print(f'过采样后数据集类别分布:\n{pd.Series(y_resampled).value_counts()}')
结果如下:
原始数据集有284807条记录,其中284315条是正常交易(类别0),492条是欺诈交易(类别1)。
过采样后数据集有568630条记录,其中正常交易仍然是284315条,但欺诈交易增加到了284315条,使得类别更加平衡。
为了更好地看到这种方法的结果,这里将其与原始数据进行比较:
def compare_plot(X, y, X_resampled, y_resampled, method): f, (ax1, ax2) = plt.subplots(1, 2) c0 = ax1.scatter(X[y==0, 0], X[y==0, 1], label='Class #0',alpha=0.5) c1 = ax1.scatter(X[y==1, 0], X[y==1, 1], label='Class #1',alpha=0.5, c='r') ax1.set_title('Original set') ax2.scatter(X_resampled[y_resampled==0, 0], X_resampled[y_resampled==0, 1], label='Class #0', alpha=.5) ax2.scatter(X_resampled[y_resampled==1, 0], X_resampled[y_resampled==1, 1], label='Class #1', alpha=.5,c='r') ax2.set_title(method) plt.figlegend((c0, c1), ('Class #0', 'Class #1'), loc='lower center', ncol=2, labelspacing=0.) plt.tight_layout(pad=3) return plt.show() print(f'Original set:\n' f'{pd.Series(y).value_counts()}\n\n' f'SMOTE:\n' f'{pd.Series(y_resampled).value_counts()}\n') compare_plot(X, y, X_resampled, y_resampled, method='SMOTE')
结果如下:
原始数据集类别分布:
0.0 284315
1.0 492
Name: count, dtype: int64
过采样后数据集类别分布:
0.0 284315
1.0 284315
Name: count, dtype: int64
SMOTE方法平衡了数据,少数群体现在与多数群体的规模相等
5. 训练和评估模型
在平衡了数据集之后,下一步训练和评估机器学习模型,以确保模型能够更准确地识别少数类(这里是欺诈交易)
这里用两种方法作对比:制定规则来识别欺诈交易,用机器学习模型来识别欺诈交易
5.1 回到原始数据,制定规则
基于原始数据,制定一些规则来识别欺诈行为,
基于对数据的观察和分析,定义一些特定的阈值来检测异常交易
例如,可以根据特征的平均值和标准差来设置阈值。
计算特征均值:
使用creditcard_data.groupby(‘Class’).mean().round(3)[[‘V1’, ‘V3’]]来计算特征V1和V3在不同类别(正常交易和欺诈交易)中的平均值。
print(creditcard_data.groupby('Class').mean().round(3)[['V1', 'V3']])
结果为:
从输出可以看到,正常交易(Class 0)和欺诈交易(Class 1)在特征V1和V3上的平均值有显著差异。
对于正常交易(Class 0),特征V1和V3的平均值分别是0.008和0.012。
对于欺诈交易(Class 1),特征V1和V3的平均值分别是-4.772和-7.033。
这表明,欺诈交易的这两个特征值明显低于正常交易。
例如,可以制定一个规则:
如果交易的V1值小于-3并且V3值小于-5,则认为该交易是欺诈行为。
这是因为在欺诈交易中,V1和V3的平均值都显著低于正常交易。
为了评估这种方法的性能,我们将把标记的欺诈案例与实际案例进行比较
5.1.1 代码
定义规则:如果交易的V1值小于-3并且V3值小于-5,则认为该交易是欺诈行为。
使用该规则标记数据集中每一条交易是否为欺诈。
import pandas as pd # 读取数据集 creditcard_data = pd.read_csv('creditcard.csv', index_col=0) # 计算特征均值 mean_values = creditcard_data.groupby('Class').mean().round(3)[['V1', 'V3']] print(mean_values) # 制定规则:V1
运行结果为
5.1.2 结果分析
计算混淆矩阵和分类报告
计算实际标签(Class)和预测标签(Predicted_Class)之间的混淆矩阵和分类报告,评估规则的性能。
混淆矩阵
Confusion Matrix:
[[283089 1226]
[ 322 170]]
283089个正常交易被正确分类为正常交易(真阴性)。
1226个正常交易被错误分类为欺诈交易(假阳性)。
322个欺诈交易被错误分类为正常交易(假阴性)。
170个欺诈交易被正确分类为欺诈交易(真阳性)。
分类报告
Precision(精确率):
类0(正常交易):精确率是1.00,表示所有被预测为正常交易的样本中,实际是正常交易的比例是100%。
换句话说,模型对正常交易的预测非常准确,没有将正常交易误判为欺诈交易。
类1(欺诈交易):精确率是0.12,表示所有被预测为欺诈交易的样本中,实际是欺诈交易的比例是12%。
这意味着在所有被标记为欺诈交易的样本中,只有12%是真正的欺诈交易,正常交易很大可能被误识别为欺诈交易。
Recall(召回率):
类0(正常交易):召回率是1.00,表示所有实际为正常交易的样本中,正确被预测为正常交易的比例是100%。
模型能够识别出所有的正常交易,没有漏掉任何正常交易。
类1(欺诈交易):召回率是0.35,表示所有实际为欺诈交易的样本中,正确被预测为欺诈交易的比例是35%。
在所有实际的欺诈交易中,只有35%被模型正确识别为欺诈交易,其余65%被误识别为正常交易。也就是说,很多欺诈交易会被误识别为正常交易。
打个比方:
假设有100个样本,模型预测有20个是欺诈交易(类1),但实际上只有2个是欺诈交易,其余18个是正常交易。模型预测80个是正常交易(类0),其中实际有78个是正常交易,其余2个是欺诈交易。
精确率(类1):
预测为欺诈的20个样本中,只有2个是实际欺诈,所以精确率 = 2/20 = 0.10。
召回率(类1):
实际为欺诈的4个样本中,只有2个被正确识别,所以召回率 = 2/4 = 0.50。
F1-score:
类0(正常交易):F1-score是1.00,是精确率和召回率的调和平均数。
类1(欺诈交易):F1-score是0.18,表示模型对欺诈交易的分类效果较差。
F1-score 同时考虑了精确率和召回率两个方面,是精确率(Precision)和召回率(Recall)的调和平均数,用来衡量模型在分类任务中的性能。F1-score 适用于不平衡数据集。
F1-score = 2 × Precision × Recall Precision + Recall \text{F1-score} = 2 \times \frac{\text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}} F1-score=2×Precision+RecallPrecision×Recall
类0(正常交易):
精确率(Precision) 和 召回率(Recall) 都是1.00。 因此,F1-score 也是1.00。
这表明模型对正常交易的分类效果非常好,能够准确且全面地识别正常交易,没有误分类和漏分类的情况。
类1(欺诈交易):
精确率(Precision) 是0.12,表示所有被预测为欺诈交易的样本中,实际是欺诈交易的比例。
召回率(Recall) 是0.35,表示所有实际为欺诈交易的样本中,正确被预测为欺诈交易的比例。
F1-score 为 0.18
F1-score = 2 × 0.12 × 0.35 0.12 + 0.35 = 2 × 0.042 0.47 ≈ 0.18 \text{F1-score} = 2 \times \frac{0.12 \times 0.35}{0.12 + 0.35} = 2 \times \frac{0.042}{0.47} \approx 0.18 F1-score=2×0.12+0.350.12×0.35=2×0.470.042≈0.18
表示模型对欺诈交易的分类效果较差。误报率较高(精确率低),漏报率也较高(召回率低)
Accuracy(准确率), 正确分类的样本数占总样本数的比例
Accuracy = TP + TN TP + TN + FP + FN \text{Accuracy} = \frac{\text{TP} + \text{TN}}{\text{TP} + \text{TN} + \text{FP} + \text{FN}} Accuracy=TP+TN+FP+FNTP+TN
混淆矩阵:
TN(True Negative):283089 - 正常交易被正确分类为正常交易
FP(False Positive):1226 - 正常交易被错误分类为欺诈交易
FN(False Negative):322 - 欺诈交易被错误分类为正常交易
TP(True Positive):170 - 欺诈交易被正确分类为欺诈交易
模型在所有样本中有99%的样本被正确分类,很高的准确率,但在不平衡数据集中,准确率并不能全面反映模型的性能,特别是对少数类(如欺诈交易)的识别能力。
支持度(Support)分类的样本数量,正常交易远多于欺诈交易,数据集极度不平衡
类0(正常交易)的样本数是284315。
类1(欺诈交易)的样本数是492。
高准确率主要是由于模型对正常交易的高识别率(几乎所有正常交易都被正确分类)
然而,模型对欺诈交易的识别效果较差,这可以从较低的类1(欺诈交易)的精确率、召回率和F1-score中看出。
Macro avg,宏平均,不同类别的指标的简单平均值。
精确率、召回率和F1-score分别是0.56、0.67和0.59。
简单平均,它反映了每个类别的指标对等的重要性。对于不平衡的数据集,少数类(如欺诈交易)的表现对这个值有较大影响
Weighted avg,加权平均,考虑了类别的样本数量,占主导地位的多数类(如正常交易)的指标。因此,即使欺诈交易的表现较差,由于正常交易占多数,整体的加权平均值仍然很高。
精确率、召回率和F1-score分别是1.00、0.99和1.00
结论
基于原始数据,制定一些规则来识别欺诈行为,检测效果不佳。
5.2 逻辑回归模型(未使用SMOTE)和逻辑回归模型(使用SMOTE)
代码及结果
import numpy as np import pandas as pd from imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report, confusion_matrix from imblearn.pipeline import Pipeline # 读取数据集 creditcard_data = pd.read_csv('creditcard.csv', index_col=0) print(f"Original dataset size: {creditcard_data.shape[0]}") # 平衡数据集 X, y = creditcard_data.iloc[:, 1:28], creditcard_data.iloc[:, 29] smote = SMOTE() X_resampled, y_resampled = smote.fit_resample(X, y) print(f"Resampled dataset size: {X_resampled.shape[0]}") # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) print(f"Training set size: {X_train.shape[0]}") print(f"Test set size: {X_test.shape[0]}") # 训练逻辑回归模型并评估 lr = LogisticRegression() lr.fit(X_train, y_train) predictions = lr.predict(X_test) print("Logistic Regression (without SMOTE):") print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud'])) print(confusion_matrix(y_test, predictions)) print(classification_report(y_test, predictions)) # 结合SMOTE和逻辑回归 pipeline = Pipeline([('SMOTE', smote), ('Logistic Regression', lr)]) pipeline.fit(X_train, y_train) predictions = pipeline.predict(X_test) print("Logistic Regression with SMOTE:") print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud'])) print(confusion_matrix(y_test, predictions)) print(classification_report(y_test, predictions))
结果如下:
数据集划分:
原始数据集被划分为训练集和测试集,其中 X_train 和 y_train 用于训练模型,X_test 和 y_test 用于评估模型。
train_test_split(X, y, test_size=0.3, random_state=0) 将 70% 的数据用作训练集,30% 的数据用作测试集。
模型训练和评估:
训练逻辑回归模型时,使用的是 X_train 和 y_train。
在测试集上进行预测,并生成混淆矩阵和分类报告时,使用的是 X_test 和 y_test。
测试集中,正常交易的样本数为 85296,欺诈交易的样本数为 147。
分类报告反映的是模型在测试集上的性能评估结果
混淆矩阵
Logistic Regression(未使用SMOTE)
Logistic Regression (without SMOTE): Flagged Fraud 0 1 Actual Fraud 0 85284 12 1 58 89 [[85284 12] [ 58 89]]
85284:正常交易正确分类(真负例)
12:正常交易误分类为欺诈交易(假阳性)
58:欺诈交易误分类为正常交易(假阴性)
89:欺诈交易正确分类(真阳性)
Logistic Regression with SMOTE(使用SMOTE)
Logistic Regression with SMOTE: Flagged Fraud 0 1 Actual Fraud 0 83101 2195 1 12 135 [[83101 2195] [ 12 135]]
83101:正常交易正确分类(真负例)
2195:正常交易误分类为欺诈交易(假阳性)
12:欺诈交易误分类为正常交易(假阴性)
135:欺诈交易正确分类(真阳性)
分类报告
Logistic Regression(未使用SMOTE)
precision recall f1-score support 0 1.00 1.00 1.00 85296 1 0.88 0.61 0.72 147 accuracy 1.00 85443 macro avg 0.94 0.80 0.86 85443 weighted avg 1.00 1.00 1.00 85443
正常交易(类0):精确率、召回率和F1-score都为1.00。
欺诈交易(类1):精确率为0.88,召回率为0.61,F1-score为0.72,模型在识别欺诈交易时漏报较多,但误报较少。
Logistic Regression(使用SMOTE)
precision recall f1-score support 0 1.00 0.97 0.99 85296 1 0.06 0.92 0.11 147 accuracy 0.97 85443 macro avg 0.53 0.95 0.55 85443 weighted avg 1.00 0.97 0.99 85443
正常交易(类0):精确率仍然为1.00,但召回率下降到0.97,F1-score为0.99。
欺诈交易(类1):精确率下降到0.06,但召回率显著提高到0.92,F1-score为0.11。能识别大部分欺诈交易,但误报较多。
未使用SMOTE:模型对正常交易的识别效果非常好,但召回率较低,对欺诈交易的识别较差。
使用SMOTE:模型对欺诈交易的识别效果显著提高,召回率达到0.92,但精确率大幅下降,误报增多。
6. 进一步
可以看到,逻辑回归模型在处理欺诈检测问题上,比简单的阈值设定规则(例如V1
为了提高逻辑回归模型的准确性,可以调整一些算法参数(如正则化参数),也可以考虑使用k-fold交叉验证而不是简单地将数据集分成训练集和测试集,交叉验证通过多次分割和训练数据集,减少了因数据分割随机性带来的误差,可以更好地评估模型的性能并选择最佳的模型参数,提高模型的稳定性和泛化能力。
也可以尝试不同的SMOTE参数,找到平衡精确率和召回率的最佳参数,如 sampling_strategy 和 k_neighbors,以找到最佳的参数组合,当欺诈记录在数据集中非常分散时,SMOTE可能会引入偏见,因为生成的合成样本可能不代表实际的欺诈模式,所以使用SMOTE会引入偏见问题。
还可以尝试一些其他的机器学习算法(如如随机森林、XGBoost),找到平衡精确率和召回率的最佳方案,从而在实际应用中更有效地识别欺诈交易
7. 随机森林模型
混淆矩阵和分类报告,显示该模型在正常交易数量远远多于欺诈交易的情况下,欺诈检测表现是比较理想的
import pandas as pd import numpy as np from imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, roc_curve from imblearn.pipeline import Pipeline import matplotlib.pyplot as plt import joblib # 数据预处理函数 def prep_data(df): X = df.iloc[:, 1:28] y = df.iloc[:, 29] return np.array(X).astype(float), np.array(y).astype(float) # 读取数据集 creditcard_data = pd.read_csv('creditcard.csv', index_col=0) # 数据预处理 X, y = prep_data(creditcard_data) # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 创建并训练随机森林模型的管道 pipeline = Pipeline([ ('scaler', StandardScaler()), ('smote', SMOTE()), ('randomforestclassifier', RandomForestClassifier(random_state=42)) ]) # 训练模型 pipeline.fit(X_train, y_train) # 预测测试集 y_pred = pipeline.predict(X_test) # 打印混淆矩阵和分类报告 print("Confusion Matrix:") print(confusion_matrix(y_test, y_pred)) print("\nClassification Report:") print(classification_report(y_test, y_pred)) # 保存模型 joblib.dump(pipeline, 'random_forest_fraud_model.pkl') print("Model saved as random_forest_fraud_model.pkl")
结果如下
8. 模型应用
关于模型的应用,需要结合实际情况优化方案,粗略的思路,例如:
目前看起来有了一个好用的模型,以后有新的交易数据进来,先把这些数据按照之前训练集的标准整理好,数据格式和特征都和训练时一致,加载模型,把整理好的数据交给模型,让它来判断哪些交易是正常的,哪些可能是欺诈的。
模型会给出一个判断结果,比如:
1 表示欺诈交易
0 表示正常交易
以下是未经运行的示例
误报处理
对于模型标记为欺诈的交易(但可能是正常交易),引入人工审核,比如,设立团队对这些交易进行复查,处理被误报的正常交易
漏报处理
对于模型没有标记为欺诈的交易(但实际上可能是欺诈交易),需要降低漏报率
例如,提高模型阈值
让模型输出每笔交易是欺诈的概率,根据业务需求调整判断标准(阈值),比如当概率大于0.5时标记为欺诈。
再如,组合多个模型提高判断的准确性
使用多个不同的模型,并取大家的综合结果
也可以进一步更新和优化训练模型