- กรณีการใช้ Data Science ในธนาคาร: การตรวจจับการทุจริต
- การเตรียมชุดข้อมูล
- การคำนวณสัดส่วนการทุจริตในชุดข้อมูล
- การใช้ SMOTE เพื่อปรับสมดุลข้อมูล
- การใช้โลจิสติกรีเกรสชัน
- สรุป
อุตสาหกรรมธนาคารเป็นหนึ่งในไม่กี่สาขาที่เก็บข้อมูลเชิงโครงสร้างจำนวนมากมาอย่างต่อเนื่องในเชิงประวัติศาสตร์ และยังเป็นหนึ่งในสาขาแรกๆ ที่นำเทคโนโลยีด้าน data science มาใช้ด้วย
Data science ถูกใช้อย่างไรในธนาคาร? ปัจจุบัน ข้อมูลได้กลายเป็นสินทรัพย์ที่มีค่าที่สุดในวงการนี้ Data science เป็นสิ่งจำเป็นสำหรับธนาคารในการแข่งขันกับคู่แข่ง ดึงดูดลูกค้าใหม่ เพิ่มความภักดีของลูกค้าเดิม ตัดสินใจเชิงข้อมูลได้มีประสิทธิภาพขึ้น เสริมศักยภาพธุรกิจ ยกระดับประสิทธิภาพการดำเนินงาน ปรับปรุงบริการ/ผลิตภัณฑ์เดิมและเปิดตัวสิ่งใหม่ๆ เสริมความปลอดภัย และด้วยผลรวมของการดำเนินการทั้งหมดนี้ ทำให้สร้างรายได้เพิ่มขึ้น จึงไม่น่าแปลกใจที่ความต้องการงานด้าน data science ส่วนใหญ่มาจากภาคธนาคาร
Data science เปิดโอกาสให้อุตสาหกรรมธนาคารสามารถทำงานได้สำเร็จในหลายด้าน รวมถึง:
- การวิเคราะห์ความเสี่ยงการลงทุน
- การพยากรณ์มูลค่าตลอดอายุการใช้งานของลูกค้า (Customer Lifetime Value)
- การแบ่งกลุ่มลูกค้า
- การพยากรณ์อัตราการสูญเสียลูกค้า (Churn)
- การทำการตลาดแบบเฉพาะบุคคล
- การวิเคราะห์ความรู้สึกของลูกค้า
- ผู้ช่วยเสมือนและแชตบอต
ด้านล่างนี้จะพาไปดูหนึ่งในกรณีการใช้งาน data science ที่พบบ่อยที่สุดในภาคธนาคารอย่างละเอียด
กรณีการใช้ Data Science ในธนาคาร: การตรวจจับการทุจริต
กิจกรรมฉ้อโกงเป็นปัญหาท้าทายไม่เฉพาะในธนาคาร แต่ยังรวมถึงหลายสาขา เช่น ภาครัฐ ประกันภัย ภาครัฐวิสาหกิจ งานขาย และสาธารณสุข ธุรกิจใดก็ตามที่มีธุรกรรมออนไลน์จำนวนมากย่อมเผชิญความเสี่ยงการทุจริตอย่างมีนัยสำคัญ อาชญากรรมทางการเงินมีหลายรูปแบบ ตั้งแต่ธุรกรรมบัตรเครดิตปลอม เช็คธนาคารปลอม เลี่ยงภาษี ฟอกเงิน การโจมตีทางไซเบอร์ ขโมยบัญชีลูกค้า อัตลักษณ์สังเคราะห์ ใบสมัครปลอม และกลโกงต่างๆ
การตรวจจับการทุจริตคือชุดของมาตรการเชิงรุกเพื่อระบุและป้องกันกิจกรรมฉ้อโกงและความสูญเสียทางการเงิน เทคนิคการวิเคราะห์หลักแบ่งได้เป็นสองกลุ่ม:
- สถิติ: การคำนวณพารามิเตอร์ทางสถิติ รีเกรสชัน การแจกแจงความน่าจะเป็น การจับคู่ข้อมูล
- ปัญญาประดิษฐ์ (AI): เหมืองข้อมูล การเรียนรู้ของเครื่อง ดีปเลิร์นนิง
การเรียนรู้ของเครื่องเป็นเสาหลักสำคัญของการตรวจจับการทุจริต ชุดเครื่องมือของมันมีสองแนวทาง:
- วิธีแบบมีผู้สอน: เพื่อนบ้านใกล้สุด k, โลจิสติกรีเกรสชัน, ซัพพอร์ตเวกเตอร์แมชชีน, ต้นไม้ตัดสินใจ, แรนดอมฟอเรสต์, การวิเคราะห์อนุกรมเวลา, โครงข่ายประสาทเทียม เป็นต้น
- วิธีแบบไม่มีผู้สอน: การวิเคราะห์คลัสเตอร์ การวิเคราะห์ลิงก์ แผนที่จัดระเบียบตัวเอง การวิเคราะห์องค์ประกอบหลัก การรู้จำความผิดปกติ เป็นต้น
ยังไม่มีกลวิธีการเรียนรู้ของเครื่องใดที่เป็นสากลและเชื่อถือได้สำหรับการตรวจจับการทุจริต สำหรับกรณีใช้งานจริง มักต้องทดสอบหลายเทคนิคหรือผสมผสานกัน คำนวณความแม่นยำการทำนายของแบบจำลอง แล้วเลือกแนวทางที่เหมาะสมที่สุด
ความท้าทายหลักของระบบตรวจจับการทุจริตคือการปรับตัวอย่างรวดเร็วต่อรูปแบบการทุจริตและกลยุทธ์ของผู้ฉ้อโกงที่เปลี่ยนแปลงตลอดเวลา และต้องค้นพบแผนการใหม่ๆ ที่ซับซ้อนยิ่งขึ้นได้อย่างทันท่วงที กรณีทุจริตมักมีสัดส่วนส่วนน้อยมากและถูกพรางอยู่ท่ามกลางธุรกรรมจริง
การเตรียมชุดข้อมูล
มาลองดูการใช้งานแมชชีนเลิร์นนิงสำหรับการตรวจจับการทุจริตบัตรเครดิตด้วยภาษา Python จะทำงานกับชุดข้อมูล creditcard_data ซึ่งเป็นตัวอย่างที่ปรับมาจากชุดข้อมูล Kaggle เรื่อง Credit Card Fraud Detection ข้อมูลต้นฉบับเป็นธุรกรรมบัตรเครดิตของผู้ถือบัตรชาวยุโรปในช่วงสองวันของเดือนกันยายน 2013
นำเข้าข้อมูลและสำรวจคร่าวๆ:
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 เราได้ตัวอย่างของคลาสส่วนน้อยมากขึ้นทันที เพื่อให้เห็นผลชัดเจนยิ่งขึ้น จะนำไปเปรียบเทียบกับข้อมูลเดิม:
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 ในทางปฏิบัติอีกครั้ง แต่ตอนนี้ขอกลับมาที่ข้อมูลดั้งเดิมและลองตรวจจับกรณีทุจริต แบบ "แนวทางดั้งเดิม" ต้องสร้างกฎบางอย่างเพื่อดักจับการทุจริต กฎเหล่านี้อาจเกี่ยวกับตำแหน่งที่ผิดปกติของธุรกรรมหรือความถี่ที่น่าสงสัย แนวคิดคือการกำหนดค่าเกณฑ์จากสถิติทั่วไป มักยึดค่าเฉลี่ยของข้อมูล แล้วใช้เกณฑ์เหล่านั้นกับคุณลักษณะของเราเพื่อระบุการทุจริต
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
การใช้โลจิสติกรีเกรสชัน
เราตรวจจับกรณีทุจริตได้ 22 จาก 50 กรณี แต่พลาดอีก 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% (9 จาก 10) เมื่อเทียบกับผลก่อนหน้าที่ 44% (22 จาก 50) และยังมีผลบวกลวงน้อยลงมาก ถือว่าเป็นการปรับปรุง
ต่อไปกลับไปที่ปัญหาคลาสไม่สมดุลที่กล่าวถึงก่อนหน้า และสำรวจว่าผลการทำนายจะดีขึ้นอีกหรือไม่หากผสานแบบจำลองโลจิสติกรีเกรสชันกับวิธีรีแซมปลิงแบบ 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-fold cross-validation แทนการแบ่งชุดข้อมูลเป็นสองส่วนเพียงอย่างเดียว สุดท้าย อาจลองอัลกอริทึมแมชชีนเลิร์นนิงอื่นๆ (เช่น ต้นไม้ตัดสินใจหรือแรนดอมฟอเรสต์) แล้วดูว่าผลลัพธ์ดีกว่าหรือไม่
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับด้านทฤษฎีและเทคนิคของการพัฒนาแบบจำลองตรวจจับการทุจริต สามารถศึกษาเนื้อหาจากคอร์ส Fraud Detection in Python ได้
