Trần Quốc Việt
← All posts

2026-04-07

Banking Domain

Hành trình của một khoản vay: Khi dữ liệu kể chuyện về lòng tin

Từ lúc tiếp cận đến khi thu hồi: Khám phá bức tranh kỹ thuật đằng sau vòng đời tín dụng — NTB vs ETB, Feature Store, Vintage Analysis, Roll Rate và cách ML len lỏi vào từng nhịp đập của ngân hàng số.

View
Lang

Tóm lược

  • Mỗi giai đoạn của một khoản vay cần loại dữ liệu và pipeline khác nhau. Đừng nhầm lẫn giữa feature marketing và feature rủi ro.
  • NTB (New to Bank) vs ETB (Existing to Bank) là phân tách cơ bản nhất: NTB dùng thin-file features (hành vi app, telco), ETB dùng lịch sử giao dịch nội bộ.
  • Feature Store (Feast + BigQuery) giải quyết vấn đề as-of semantics — đảm bảo không có data leakage qua point-in-time join.
  • Vintage AnalysisRoll Rate Matrix là hai công cụ cốt lõi trong Servicing và Collections — không phải ML model nào cũng thay thế được chúng.

Giới thiệu

Disclaimer: Bài viết này chia sẻ dưới góc độ kỹ thuật về cách dữ liệu và ML vận hành trong tín dụng bán lẻ. Mỗi ngân hàng, mỗi quốc gia sẽ có quy định riêng — đây không thay thế cho tư vấn pháp lý hay chính sách rủi ro chính thức.

Bạn đã bao giờ tự hỏi điều gì xảy ra sau khi nhấn nút "Đăng ký vay" trên ứng dụng ngân hàng số chưa? Đằng sau giao diện mượt mà đó là một hành trình dữ liệu phức tạp, với nhiều pipeline chạy song song ở những tần suất và grain hoàn toàn khác nhau.

NTB vs ETB: Phân tách cơ bản nhất

Trước khi nói về vòng đời tín dụng, cần hiểu rõ hai phân khúc khách hàng chính, vì chúng đòi hỏi chiến lược dữ liệu hoàn toàn khác nhau:

Tiêu chíNTB (New to Bank)ETB (Existing to Bank)
Lịch sử nội bộKhông cóCó (giao dịch, sản phẩm)
Feature chínhApp behavior, telco, bureauAvg balance 6M, transaction patterns
Model approachThin-file model, bureau-heavyRich behavioral model
Data challengeCold start, leakage từ bureauPoint-in-time correctness

NTB khó hơn vì dữ liệu ít, và rủi ro leakage cao hơn (bureau data có thể chứa thông tin "hậu sự kiện"). ETB dễ hơn nhưng phức tạp hơn ở as-of semantics — cần biết chính xác balance của khách hàng tại ngày nộp đơn, không phải ngày hôm nay.

Hành trình bốn giai đoạn của tín dụng

Giai đoạn 1 — Tiếp cận (Acquisition)

Mục tiêu: tìm đúng khách hàng để chào mời. Data chủ yếu là behavioral (hành vi trên app, click marketing) và demographic. Xử lý batch.

Pipeline điển hình:

  • Airflow DAG chạy daily: aggregate behavioral features → BigQuery mart
  • Propensity model: dự báo khả năng khách hàng quan tâm đến sản phẩm vay
  • Lưu ý: Features ở giai đoạn này là marketing features, KHÔNG được dùng trực tiếp cho credit model

Giai đoạn 2 — Quyết định (Decisioning)

Giai đoạn nóng nhất: latency là sống còn. Hệ thống phải trả về quyết định trong < 2 giây.

python
# Feast point-in-time join  đảm bảo as-of semantics
from feast import FeatureStore

store = FeatureStore(repo_path=".")

entity_df = pd.DataFrame({
    "customer_id": applications["customer_id"],
    "event_timestamp": applications["application_date"],  # as-of cutoff
})

# NTB features: app behavioral (7-day, 30-day)
ntb_features = store.get_historical_features(
    entity_df=entity_df,
    features=[
        "ntb_feature_view:app_session_count_7d",
        "ntb_feature_view:avg_session_duration_30d",
        "ntb_feature_view:product_view_count_30d",
    ],
)

# ETB features: internal transaction history
etb_features = store.get_historical_features(
    entity_df=entity_df,
    features=[
        "etb_feature_view:avg_balance_6m",
        "etb_feature_view:salary_credit_count_3m",
        "etb_feature_view:debit_transaction_amt_1m",
    ],
)

Point-in-time join đảm bảo event_timestamp của feature ≤ application_date — ngăn chặn data leakage từ tương lai vào past.

Giai đoạn 3 — Quản lý (Servicing)

Khoản vay đã giải ngân. Nhiệm vụ: phát hiện sớm dấu hiệu rủi ro.

Vintage Analysis là công cụ quan trọng nhất ở giai đoạn này:

sql
-- Vintage analysis: bad rate by origination cohort
-- Track how each monthly cohort performs over time
SELECT
  DATE_TRUNC(origination_date, MONTH)  AS vintage_month,
  DATE_DIFF(observation_date, origination_date, MONTH) AS months_on_book,
  COUNT(*) AS total_loans,
  COUNTIF(dpd >= 30) AS dpd30_count,
  ROUND(COUNTIF(dpd >= 30) / COUNT(*), 4) AS bad_rate_dpd30
FROM loan_performance
WHERE observation_date <= CURRENT_DATE()
GROUP BY 1, 2
ORDER BY 1, 2

Vintage analysis giúp trả lời: "Cohort tháng 3 đang worse hơn cohort tháng 1 ở cùng MOB (Months on Book) không?" — nếu có, đó là early warning signal cần điều tra ngay.

Giai đoạn 4 — Thu hồi (Collections)

Khi khách hàng bắt đầu trễ hạn, Roll Rate Matrix là công cụ để forecast migration giữa các bucket delinquency:

Từ \ ĐếnCurrentDPD 1-29DPD 30-59DPD 60-89DPD 90+
Current96%4%
DPD 1-2935%30%35%
DPD 30-5915%10%25%50%
DPD 60-895%5%10%20%60%

Roll rate giúp: (1) forecast provisioning requirement, (2) ưu tiên đội thu hồi tập trung vào bucket nào, (3) detect deterioration sớm khi roll rate từ Current → DPD tăng bất thường.

Những "hố đen" cần tránh

1. Dùng chung data warehouse cho tất cả giai đoạn

Mỗi giai đoạn cần grain khác nhau:

  • Acquisition: customer-level daily snapshot
  • Decisioning: application-level point-in-time
  • Servicing: loan-level monthly observation
  • Collections: account-level weekly

Nhồi tất cả vào một bảng dẫn đến fan-out joins sai grain và temporal leakage.

2. Quên as-of semantics khi train model

python
# SAI: join loan data với current balance (leakage!)
df = loans.merge(balances, on='customer_id')  # balances  "hôm nay"

# ĐÚNG: chỉ lấy balance tại thời điểm application
df = loans.merge(
    balances[balances['snapshot_date'] <= loans['application_date']],
    on=['customer_id', 'snapshot_date'],  # point-in-time join
)

3. Aggregate metrics che giấu vintage deterioration

Nhìn vào "overall bad rate = 2%" không nói lên gì. Bad rate của cohort tháng 3/2026 đang worse 40% so với cohort tháng 1/2026 ở cùng MOB — đó mới là thông tin đáng lo ngại.

Bảng tóm tắt kỹ thuật

Giai đoạnGrainFrequencyKey ML taskData challenge
AcquisitionCustomer-dayDaily batchPropensity modelMarketing vs risk feature mixing
DecisioningApplicationReal-timeCredit scoringAs-of semantics, latency < 2s
ServicingLoan-monthDaily/WeeklyEarly warningVintage cohort tracking
CollectionsAccount-weekWeeklyRecovery optimizationCompliance, communication rules

Kết luận

Hiểu vòng đời tín dụng giúp chúng ta thoát khỏi vỏ bọc "kỹ sư chỉ biết code". NTB hay ETB, Acquisition hay Collections — mỗi giai đoạn có ngôn ngữ dữ liệu riêng. Khi bạn nói đúng ngôn ngữ đó, những dòng code của mình mới thực sự bảo vệ được đồng tiền và lòng tin.


Bài liên quan / Related posts