ข้ามไปยังเนื้อหาหลัก

Data Science ในธนาคาร: การตรวจจับการทุจริต

เรียนรู้วิธีการประยุกต์ใช้ data science ในภาคธนาคารผ่านกรณีการใช้งานที่พบบ่อยที่สุดกรณีหนึ่ง: การตรวจจับการทุจริต
อัปเดตแล้ว 31 ส.ค. 2569  · 11 นาที อ่าน

สำรวจด้วย AI

ChatGPTClaudePerplexity

ภาพประกอบแนวคิดฟินเทค

อุตสาหกรรมธนาคารเป็นหนึ่งในไม่กี่สาขาที่เก็บข้อมูลเชิงโครงสร้างจำนวนมากมาอย่างต่อเนื่องในเชิงประวัติศาสตร์ และยังเป็นหนึ่งในสาขาแรกๆ ที่นำเทคโนโลยีด้าน 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

จะเห็นว่าเมื่อใช้ 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

การใช้โลจิสติกรีเกรสชัน 

เราตรวจจับกรณีทุจริตได้ 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 ได้

หัวข้อ
วิทยาการข้อมูล
แมชชีนเลิร์นนิง