跳至内容

银行业中的数据科学:欺诈检测

通过探索最常见的用例之一——欺诈检测,了解数据科学在银行业中的落地方式。
更新 2026年8月31日  · 11分钟

用 AI 探索

ChatGPTClaudePerplexity

金融科技概念插图

银行业历来积累了大量结构化数据,也是最早应用数据科学技术的领域之一。

数据科学在银行业如何发挥作用?如今,数据已成为该领域最宝贵的资产。数据科学是银行保持竞争力、吸引更多客户、提升现有客户忠诚度、做出更高效的数据驱动决策、推动业务发展、提升运营效率、改进既有产品/服务并推出新产品、强化安全性的必要条件,最终带来更高收益。难怪数据科学岗位需求的大头来自银行业。

数据科学使银行业能够成功开展众多任务,包括: 

  • 投资风险分析
  • 客户终身价值预测
  • 客户细分
  • 客户流失率预测
  • 个性化营销
  • 客户情感分析
  • 虚拟助手和聊天机器人

下面我们将深入了解银行业中最常见的数据科学用例之一。

银行业中的数据科学用例:检测欺诈 

欺诈活动不仅在银行业,在政府、保险、公共部门、零售和医疗等诸多领域都构成严峻挑战。任何高频在线交易的业务都面临显著的欺诈风险。金融犯罪形式多样,包括信用卡欺诈交易、伪造支票、逃税、洗钱、网络攻击、账户盗用、综合身份、虚假申请以及各类诈骗。

欺诈检测是一系列主动措施,用于识别并预防欺诈活动和财务损失。其主要分析技术可分为两大类:

  • 统计方法:统计参数计算、回归、概率分布、数据匹配
  • 人工智能(AI):数据挖掘、机器学习、深度学习

机器学习是欺诈检测的重要支柱。其工具箱主要提供两类方法:

  • 有监督方法:k 近邻、逻辑回归、支持向量机、决策树、随机森林、时间序列分析、神经网络等
  • 无监督方法:聚类分析、关联分析、自组织映射、主成分分析、异常检测等

并不存在一种通用且可靠的欺诈检测算法。在真实世界的用例中,通常需要测试多种技术或其组合,计算模型的预测准确率,从而选出最优方案。

欺诈检测系统的主要挑战在于必须迅速适应不断变化的欺诈模式和手法,并及时发现新的、愈发复杂的方案。欺诈样本在交易中始终占少数,而且隐藏得很深。

准备数据集

让我们用 Python 实现信用卡欺诈检测。我们将使用 creditcard_data 数据集,这是一份来自 Kaggle 数据集 Credit Card Fraud Detection 的改造示例。原始数据为 2013 年 9 月两天内欧洲持卡人的信用卡交易记录。

先导入数据并快速浏览:

import pandas as pd

creditcard_data = pd.read_csv('creditcard_data.csv', index_col=0)
print(creditcard_data.info())
print('\n')
pd.options.display.max_columns = len(creditcard_data)
print(creditcard_data.head(3))
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5050 entries, 0 to 5049
Data columns (total 30 columns):
#   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
0   V1      5050 non-null   float64
1   V2      5050 non-null   float64
2   V3      5050 non-null   float64
3   V4      5050 non-null   float64
4   V5      5050 non-null   float64
5   V6      5050 non-null   float64
6   V7      5050 non-null   float64
7   V8      5050 non-null   float64
8   V9      5050 non-null   float64
9   V10     5050 non-null   float64
10  V11     5050 non-null   float64
11  V12     5050 non-null   float64
12  V13     5050 non-null   float64
13  V14     5050 non-null   float64
14  V15     5050 non-null   float64
15  V16     5050 non-null   float64
16  V17     5050 non-null   float64
17  V18     5050 non-null   float64
18  V19     5050 non-null   float64
19  V20     5050 non-null   float64
20  V21     5050 non-null   float64
21  V22     5050 non-null   float64
22  V23     5050 non-null   float64
23  V24     5050 non-null   float64
24  V25     5050 non-null   float64
25  V26     5050 non-null   float64
26  V27     5050 non-null   float64
27  V28     5050 non-null   float64
28  Amount  5050 non-null   float64
29  Class   5050 non-null   int64 
dtypes: float64(29), int64(1)
memory usage: 1.2 MB


        V1        V2        V3        V4        V5        V6        V7  \
0  1.725265 -1.337256 -1.012687 -0.361656 -1.431611 -1.098681 -0.842274  
1  0.683254 -1.681875  0.533349 -0.326064 -1.455603  0.101832 -0.520590  
2  1.067973 -0.656667  1.029738  0.253899 -1.172715  0.073232 -0.745771  

        V8        V9       V10       V11       V12       V13       V14  \
0 -0.026594 -0.032409  0.215113  1.618952 -0.654046 -1.442665 -1.546538  
1  0.114036 -0.601760  0.444011  1.521570  0.499202 -0.127849 -0.237253  
2  0.249803  1.383057 -0.483771 -0.782780  0.005242 -1.273288 -0.269260  

        V15       V16       V17       V18       V19       V20       V21  \
0 -0.230008  1.785539  1.419793  0.071666  0.233031  0.275911  0.414524  
1 -0.752351  0.667190  0.724785 -1.736615  0.702088  0.638186  0.116898  
2  0.091287 -0.347973  0.495328 -0.925949  0.099138 -0.083859 -0.189315  

        V22       V23       V24       V25       V26       V27       V28  \
0  0.793434  0.028887  0.419421 -0.367529 -0.155634 -0.015768  0.010790  
1 -0.304605 -0.125547  0.244848  0.069163 -0.460712 -0.017068  0.063542  
2 -0.426743  0.079539  0.129692  0.002778  0.970498 -0.035056  0.017313  

  Amount  Class 
0  189.00      0 
1  315.17      0 
2   59.98      0 

数据集包含以下变量:

  • 数值编码变量 V1 至 V28,是通过 PCA 转换得到的主成分。出于保密原因,未提供原始特征的背景信息。
  • Amount 变量表示交易金额。
  • Class 变量表示该交易是否为欺诈:欺诈为 1,非欺诈为 0。

通常情况下,欺诈在交易清单中所占比例很低。然而,机器学习算法通常在各类样本分布较为均衡时表现更好。否则,可供学习的欺诈样本过少。这个问题称为类别不平衡。

计算数据集中的欺诈占比

我们来计算欺诈交易占全部交易数量的百分比:

round(creditcard_data['Class'].value_counts()*100/len(creditcard_data)).convert_dtypes()
0    99
1     1
Name: Class, dtype: Int64

并绘制图表直观展示欺诈与非欺诈的数据点:

import matplotlib.pyplot as plt
import numpy as np

def prep_data(df):
    X = df.iloc[:, 1:28]
    X = np.array(X).astype(float)
    y = df.iloc[:, 29]
    y = np.array(y).astype(float)
    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)

欺诈交易

使用 SMOTE 重新平衡数据 

现在可以确认,欺诈交易占比极低,确实存在类别不平衡问题。为了解决这一问题,我们可以使用合成少数类过采样技术(SMOTE)对数据进行再平衡。与随机过采样不同,SMOTE 更为精细,并非简单复制观测值,而是利用欺诈样本的近邻特征生成新的合成样本,使之与少数类中现有观测较为相似。让我们将 SMOTE 应用于信用卡数据:

from imblearn.over_sampling import SMOTE

method = SMOTE()
X_resampled, y_resampled = method.fit_resample(X, y)
plot_data(X_resampled, y_resampled)

SMOTE 图表

如您所见,使用 SMOTE 后,少数类的观测数量显著增加。为了更直观地比较,我们将其与原始数据放在一起展示:

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.value_counts(pd.Series(y))}\n\n'
      f'SMOTE:\n'
      f'{pd.value_counts(pd.Series(y_resampled))}\n')

compare_plot(X, y, X_resampled, y_resampled, method='SMOTE')
Original set:
0.0    5000
1.0      50
dtype: int64


SMOTE:
0.0    5000
1.0    5000
dtype: int64

Smote 方法图表

因此,SMOTE 方法将数据完全平衡了,少数类的规模现已与多数类相当。

我们稍后还会回到 SMOTE 的实际应用。现在先回到原始数据,尝试识别欺诈案例。按照“老派”做法,需要制定一些规则来捕捉欺诈。例如,交易地点异常或交易频率可疑等。思路是基于常见统计量(通常是均值)设定阈值,并用这些阈值在特征上检测欺诈。

print(creditcard_data.groupby('Class').mean().round(3)[['V1', 'V3']])
        V1     V3
Class             
0      0.035  0.037
1     -4.985 -7.294

在本例中,我们应用如下条件:V1 < -3 且 V3 < -5。随后,将标记为欺诈的交易与真实欺诈进行对比以评估该方法表现:

creditcard_data['flag_as_fraud'] = np.where(np.logical_and(creditcard_data['V1']<-3, creditcard_data['V3']<-5), 1, 0)
print(pd.crosstab(creditcard_data['Class'], creditcard_data['flag_as_fraud'], rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud     0   1
Actual Fraud          
0              4984  16
1                28  22

应用逻辑回归 

我们识别出 50 起欺诈中的 22 起,但漏掉了 28 起,同时产生了 16 个误报。看看机器学习技术能否取得更好结果。

下面我们在信用卡数据上实现一个简单的逻辑回归分类器来识别欺诈,并将结果用混淆矩阵可视化:

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

lr = LogisticRegression()
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud   0.0  1.0
Actual Fraud           
0.0            1504    1
1.0             1      9

需要注意的是,这里的混淆矩阵观测数较少,因为我们仅使用测试集来评估模型,即只用了整个数据集的 30%。

我们捕捉到更高比例的欺诈:90%(10 起中的 9 起),相比之前的 44%(50 起中的 22 起)。误报也明显减少,这是一个提升。

现在回到此前的类别不平衡问题,看看将逻辑回归与 SMOTE 结合,是否能进一步提高预测效果。为高效地一次性完成,我们定义一个流水线并在数据上运行:

from imblearn.pipeline import Pipeline

# Defining which resampling method and which ML model to use in the pipeline
resampling = SMOTE()
lr = LogisticRegression()

pipeline = Pipeline([('SMOTE', resampling), ('Logistic Regression', lr)])
pipeline.fit(X_train, y_train)
predictions = pipeline.predict(X_test)
print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud   0.0  1.0
Actual Fraud           
0.0            1496    9
1.0               1    9

如您所见,在本例中 SMOTE 并未带来改进:我们仍然捕捉到 90% 的欺诈,同时误报略有上升。原因在于,重采样并非在所有情况下都能提升效果。当欺诈样本在数据中分布很分散时,其近邻未必也是欺诈样本,使用 SMOTE 可能会引入偏差。

结论 

接下来,可以通过调参来提升逻辑回归模型的准确率;也可考虑使用 K 折交叉验证,而不是简单地将数据集一分为二。最后,还可以尝试其他机器学习算法(如决策树或随机森林)并比较其效果。 

如果您想进一步了解欺诈检测模型实现的理论与技术细节,可以查看 Fraud Detection in Python 课程的相关资料。

主题
数据科学
机器学习