- 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
- Chuẩn bị bộ dữ liệu
- Tính toán gian lận trong bộ dữ liệu
- Sử dụng SMOTE để cân bằng lại dữ liệu
- Áp dụng hồi quy logistic
- Kết luận
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)

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)

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

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.
