Chuyển đến nội dung chính

Khoa học dữ liệu trong ngân hàng: Phát hiện gian lận

Tìm hiểu cách khoa học dữ liệu được triển khai trong lĩnh vực ngân hàng bằng cách khám phá một trong những trường hợp sử dụng phổ biến nhất: phát hiện gian lận.
Đã cập nhật 31 thg 8, 2026  · 11 phút đọc

Khám phá với AI

ChatGPTClaudePerplexity

Minh hoạ khái niệm Fintech

Ngân hàng là một trong những lĩnh vực may mắn khi lịch sử đã thu thập được rất nhiều dữ liệu có cấu trúc, đồng thời cũng là một trong những lĩnh vực đầu tiên áp dụng các công nghệ khoa học dữ liệu.

Khoa học dữ liệu được sử dụng trong ngân hàng như thế nào? Ngày nay, dữ liệu đã trở thành tài sản quý giá nhất trong lĩnh vực này. Khoa học dữ liệu là yêu cầu tất yếu để các ngân hàng bắt kịp đối thủ, thu hút thêm khách hàng, tăng lòng trung thành của khách hàng hiện hữu, đưa ra các quyết định dựa trên dữ liệu hiệu quả hơn, thúc đẩy hoạt động kinh doanh, nâng cao hiệu quả vận hành, cải thiện dịch vụ/sản phẩm hiện có và giới thiệu những dịch vụ/sản phẩm mới, củng cố an ninh, và, là hệ quả của tất cả những hành động đó, gia tăng doanh thu. Không có gì ngạc nhiên khi phần lớn nhu cầu tuyển dụng trong khoa học dữ liệu đến từ lĩnh vực ngân hàng.

Khoa học dữ liệu cho phép ngành ngân hàng thực hiện hiệu quả nhiều nhiệm vụ, bao gồm: 

  • phân tích rủi ro đầu tư
  • dự đoán giá trị vòng đời khách hàng
  • phân khúc khách hàng
  • dự đoán tỷ lệ rời bỏ của khách hàng
  • tiếp thị cá nhân hoá
  • phân tích cảm xúc của khách hàng
  • trợ lý ảo và chatbot

Bên dưới, chúng ta sẽ xem xét kỹ hơn một trong những trường hợp sử dụng phổ biến nhất của khoa học dữ liệu trong ngân hàng.

Trường hợp sử dụng khoa học dữ liệu trong ngân hàng: Phát hiện gian lận 

Các hoạt động gian lận là một vấn đề thách thức không chỉ trong ngân hàng mà còn trong nhiều lĩnh vực khác như chính phủ, bảo hiểm, khu vực công, bán hàng và chăm sóc sức khỏe. Bất kỳ doanh nghiệp nào xử lý số lượng lớn giao dịch trực tuyến đều đối mặt với rủi ro gian lận đáng kể. Tội phạm tài chính có thể tồn tại dưới nhiều hình thức, bao gồm giao dịch thẻ tín dụng gian lận, séc ngân hàng giả mạo, trốn thuế, rửa tiền, tấn công mạng, trộm tài khoản khách hàng, danh tính tổng hợp, hồ sơ đăng ký giả và lừa đảo.

Phát hiện gian lận là tập hợp các biện pháp chủ động nhằm xác định và ngăn chặn các hoạt động gian lận và tổn thất tài chính. Các kỹ thuật phân tích chính của nó có thể được chia thành hai nhóm:

  • Thống kê: tính tham số thống kê, hồi quy, phân phối xác suất, đối sánh dữ liệu
  • Trí tuệ nhân tạo (AI): khai phá dữ liệu, học máy, học sâu

Học máy là một trụ cột thiết yếu cho phát hiện gian lận. Bộ công cụ của nó cung cấp hai cách tiếp cận:

  • Phương pháp có giám sát: k-láng giềng gần nhất, hồi quy logistic, máy vector hỗ trợ, cây quyết định, rừng ngẫu nhiên, phân tích chuỗi thời gian, mạng nơ-ron, v.v.
  • Phương pháp không giám sát: phân cụm, phân tích liên kết, bản đồ tự tổ chức, phân tích thành phần chính, nhận dạng bất thường, v.v.

Không có một thuật toán học máy nào mang tính phổ quát và đáng tin cậy cho phát hiện gian lận. Thay vào đó, trong các trường hợp sử dụng thực tế, thường sẽ thử nghiệm một vài kỹ thuật hoặc kết hợp của chúng, tính toán độ chính xác dự báo của mô hình và chọn ra cách tiếp cận tối ưu.

Thách thức chính đối với các hệ thống phát hiện gian lận là nhanh chóng thích nghi với các mẫu gian lận và thủ đoạn của kẻ gian luôn thay đổi, đồng thời kịp thời phát hiện ra những chiêu thức mới ngày càng tinh vi. Các trường hợp gian lận luôn chiếm thiểu số và được che giấu kỹ giữa các giao dịch hợp lệ.

Chuẩn bị bộ dữ liệu

Hãy khám phá một triển khai học máy để phát hiện gian lận thẻ tín dụng bằng ngôn ngữ lập trình Python. Chúng ta sẽ làm việc với bộ dữ liệu creditcard_data, là mẫu đã được chỉnh sửa từ bộ dữ liệu trên Kaggle về Phát hiện gian lận thẻ tín dụng. Dữ liệu gốc đại diện cho các giao dịch được thực hiện bằng thẻ tín dụng của chủ thẻ châu Âu trong hai ngày của tháng 9 năm 2013.

Hãy nhập dữ liệu và xem nhanh:

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 

Bộ dữ liệu chứa các biến sau:

  • Các biến được mã hóa số từ V1 đến V28 là các thành phần chính thu được từ phép biến đổi PCA. Do vấn đề bảo mật, không có thông tin nền về các đặc trưng gốc được cung cấp.
  • Biến Amount đại diện cho số tiền giao dịch.
  • Biến Class cho biết giao dịch có gian lận (1) hay không (0).

Theo bản chất, các trường hợp gian lận may mắn là luôn chiếm tỷ lệ cực nhỏ trong bất kỳ danh sách giao dịch nào. Tuy nhiên, các thuật toán học máy thường hoạt động tốt nhất khi các lớp khác nhau trong bộ dữ liệu có mặt tương đối cân bằng.  Nếu không, sẽ có quá ít dữ liệu để học. Vấn đề này được gọi là mất cân bằng lớp.

Tính toán gian lận trong bộ dữ liệu

Hãy tính phần trăm giao dịch gian lận trên tổng số giao dịch trong bộ dữ liệu của chúng ta:

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

và tạo một biểu đồ để trực quan hóa các điểm dữ liệu gian lận so với không gian lận:

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)

Giao dịch gian lận

Sử dụng SMOTE để cân bằng lại dữ liệu 

Giờ đây, chúng ta có thể xác nhận rằng tỷ lệ giao dịch gian lận là rất thấp và chúng ta đang gặp vấn đề mất cân bằng lớp. Để khắc phục, ta có thể cân bằng lại dữ liệu bằng kỹ thuật lấy mẫu tăng cường cho lớp thiểu số tổng hợp (SMOTE). Khác với lấy mẫu ngẫu nhiên, SMOTE tinh vi hơn một chút vì nó không chỉ tạo bản sao y hệt của các quan sát. Thay vào đó, nó sử dụng đặc trưng của các hàng xóm gần nhất của các trường hợp gian lận để tạo ra các mẫu tổng hợp mới khá giống với các quan sát hiện có trong lớp thiểu số. Hãy áp dụng SMOTE cho dữ liệu thẻ tín dụng của chúng ta:

from imblearn.over_sampling import SMOTE

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

Biểu đồ SMOTE

Như chúng ta thấy, sử dụng SMOTE ngay lập tức cho ta nhiều quan sát hơn thuộc lớp thiểu số. Để thấy rõ kết quả của cách tiếp cận này hơn nữa, chúng ta sẽ so sánh chúng với dữ liệu gốc:

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

Biểu đồ phương pháp Smote

Vì vậy, phương pháp SMOTE đã cân bằng hoàn toàn dữ liệu của chúng ta, và lớp thiểu số giờ đây có kích thước bằng với lớp đa số.

Chúng ta sẽ quay lại ứng dụng thực tế của phương pháp SMOTE sau, nhưng hiện tại, hãy trở lại dữ liệu gốc và thử phát hiện các trường hợp gian lận. Theo cách "cổ điển", chúng ta phải tạo một số quy tắc để bắt gian lận. Những quy tắc như vậy có thể liên quan, chẳng hạn, đến vị trí giao dịch bất thường hoặc tần suất giao dịch đáng ngờ. Ý tưởng là xác định các ngưỡng dựa trên thống kê phổ biến, thường là trên giá trị trung bình của các quan sát, và sử dụng các ngưỡng đó trên các đặc trưng của chúng ta để phát hiện gian lận.

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

Trong trường hợp cụ thể này, hãy áp dụng các điều kiện sau: V1 < -3 và V3 < -5. Sau đó, để ước lượng hiệu quả của cách tiếp cận này, chúng ta sẽ so sánh các trường hợp bị gắn cờ gian lận với các trường hợp gian lận thực tế:

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

Áp dụng hồi quy logistic 

Chúng ta phát hiện được 22 trên 50 trường hợp gian lận, nhưng không phát hiện được 28 trường hợp còn lại, và có 16 dương tính giả. Hãy xem liệu sử dụng các kỹ thuật học máy có thể vượt qua những kết quả đó hay không.

Bây giờ chúng ta sẽ triển khai một thuật toán phân loại hồi quy logistic đơn giản trên dữ liệu thẻ tín dụng để nhận diện các trường hợp gian lận và sau đó trực quan hóa kết quả trên ma trận nhầm lẫn:

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

Lưu ý rằng ở đây chúng ta có ít quan sát hơn trong ma trận nhầm lẫn vì chỉ sử dụng tập kiểm tra để tính toán kết quả mô hình, tức là chỉ 30% của toàn bộ bộ dữ liệu.

Chúng ta bắt được tỷ lệ cao hơn các trường hợp gian lận: 90% (9 trên 10), so với kết quả trước đó là 44% (22 trên 50). Chúng ta cũng có ít dương tính giả hơn trước, nên đó là một cải thiện.

Giờ hãy quay lại vấn đề mất cân bằng lớp đã thảo luận trước đó và xem liệu chúng ta có thể cải thiện kết quả dự đoán hơn nữa bằng cách kết hợp mô hình hồi quy logistic với phương pháp lấy mẫu lại SMOTE hay không. Để thực hiện hiệu quả và trong một lần, chúng ta cần định nghĩa một pipeline và chạy nó trên dữ liệu:

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

Như ta thấy, trong trường hợp này SMOTE không mang lại cải thiện: chúng ta vẫn bắt được 90% các trường hợp gian lận và, hơn nữa, số dương tính giả hơi cao hơn. Lý do là việc lấy mẫu lại không nhất thiết dẫn đến kết quả tốt hơn trong mọi trường hợp. Khi các trường hợp gian lận phân tán rộng trong dữ liệu, các hàng xóm gần nhất của chúng không nhất thiết cũng là trường hợp gian lận, vì vậy sử dụng SMOTE có thể đưa vào sai lệch.

Kết luận 

Một hướng đi khả dĩ để nâng cao độ chính xác của mô hình hồi quy logistic là tinh chỉnh một số tham số của thuật toán. Cũng có thể cân nhắc sử dụng kiểm định chéo k-fold thay vì chỉ chia bộ dữ liệu thành hai phần. Cuối cùng, chúng ta có thể thử một số thuật toán học máy khác (ví dụ, cây quyết định hoặc rừng ngẫu nhiên) và xem liệu chúng có cho kết quả tốt hơn không. 

Nếu bạn muốn tìm hiểu thêm về các khía cạnh lý thuyết và kỹ thuật của việc triển khai mô hình phát hiện gian lận, bạn có thể khám phá tài liệu của khoá học Fraud Detection in Python.

Chủ đề
Khoa học Dữ liệu
Machine Learning
Có liên quan

blogs

Claude Opus 4.6: Tính năng, Điểm chuẩn, Bài kiểm tra thực hành và hơn thế nữa

Mô hình mới nhất của Anthropic dẫn đầu ở mã hóa tác tử và lập luận phức tạp. Thêm vào đó, nó có cửa sổ ngữ cảnh 1M.
Matt Crabtree's photo

Matt Crabtree

10 phút

Xem ThêmXem Thêm