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

2026-04-25

Banking Domain

Champion-Challenger: Cách prove model mới mà không cần đặt cược toàn bộ

Model mới backtest AUC cao hơn 3%. Risk committee hỏi: 'Trên production thật thì sao?' Champion-Challenger là cách trả lời câu hỏi đó mà không cần gamble.

View
Lang

Tóm tắt

Champion-Challenger (C/C) là framework thử nghiệm model mới trên traffic production thật, với tỷ lệ nhỏ, trong một khoảng thời gian đủ dài để có outcome. Champion là model đang chạy. Challenger là ứng viên thay thế. Sau khi có đủ dữ liệu, so sánh bằng bằng chứng — không phải bằng niềm tin.


Tại sao backtest không đủ

Giả sử bạn vừa train xong model mới. Trên tập OOT, AUC tăng từ 0.72 lên 0.75. Bạn mang kết quả đó vào risk committee và đề xuất deploy.

Risk committee hỏi: "OOT của bạn là data từ 6 tháng trước. Population hiện tại có giống không? Policy có thay đổi không? Nếu model mới cho approval rate thấp hơn, chúng ta mất bao nhiêu doanh thu?"

Đây không phải câu hỏi khó chịu — đây là câu hỏi đúng. Backtest trả lời "model này đã hoạt động tốt trong quá khứ." C/C trả lời "model này đang hoạt động tốt trong hiện tại, trên khách hàng thật, với policy hiện tại."


Metaphor: Tuyển thủ dự bị

Không có HLV nào đưa tân binh vào sân chính từ phút đầu mà không có thời gian warm-up thực chiến. Tân binh được cho vào sân ở những trận ít áp lực hơn — hoặc trong 15 phút cuối khi tỷ số đã được định đoạt.

C/C hoạt động y hệt: Challenger được "vào sân" với một phần nhỏ traffic, trong điều kiện thật, nhưng rủi ro được kiểm soát. Nếu tốt, lên sân chính. Nếu không, bench lại không ai bị thiệt hại nặng.


Framework 4 bước

Bước 1: Define success criteria TRƯỚC khi test

Đây là bước quan trọng nhất — và bị bỏ qua nhiều nhất.

Trước khi split traffic, viết rõ: "Challenger win khi..."

  • Gini trên real traffic cao hơn Champion ≥ 2 percentage points
  • Approval rate không giảm hơn 1%
  • DPD30 rate (early delinquency) trong 3 tháng đầu không tệ hơn Champion

Không define sau khi thấy kết quả. Nếu bạn define criteria sau, bạn đang tìm kiếm confirmation, không phải evidence.

Bước 2: Traffic split

Tỷ lệ split phụ thuộc vào risk appetite và volume:

VolumeSplit tiêu biểuLý do
Cao (>5,000 app/tháng)90/10Đủ sample cho Challenger
Trung bình (1,000–5,000)95/5Giảm exposure của Challenger
Thấp (<1,000)Cân nhắc lạiCần sample size đủ lớn để có ý nghĩa thống kê

Quan trọng: Split phải ngẫu nhiên và stratified. Không để Challenger nhận toàn bộ applicant từ một channel cụ thể, một region, hay một loan officer — vì đó không còn là fair comparison nữa. Randomize theo application ID hoặc customer ID.

Bước 3: Outcome window

Credit không phải là e-commerce — bạn không biết "kết quả" trong vài ngày. Cần đủ thời gian để outcome materialise:

MetricMinimum window
DPD30 (early signal)1 tháng
DPD90 (default signal)3 tháng
Charge-off rate6–12 tháng
Vintage Gini6–12 tháng

Đừng rút kết luận sau 3 tuần vì "trông có vẻ tốt." Early delinquency rates trong 3 tuần đầu không đại diện cho long-term performance. Kiên nhẫn là kỷ luật quan trọng nhất trong C/C.

Bước 4: Decision framework

Sau khi có đủ outcome:

Kết quảHành động
Challenger win rõ ràng (all criteria met)Promote Challenger 100%, archive Champion
Challenger win nhẹ (đa số criteria met)Tăng traffic Challenger lên 30–50%, extend test
Challenger neutral (mixed signals)Giữ Champion, deep-dive vào segment nào Challenger tệ
Challenger thua (at least 1 critical criterion failed)Discard, post-mortem, không deploy

Edge cases thực tế

Seasonality làm lệch kết quả. Nếu test vào mùa Tết, applicant profile thay đổi hoàn toàn — kết quả không generalize ra ngoài mùa đó. Tốt nhất là test đủ dài để bao phủ ít nhất 1 cycle seasonal, hoặc explicitly document limitation.

Policy thay đổi trong khi test. Đây là killer của mọi C/C. Nếu risk appetite thay đổi (nới lỏng hay thắt chặt) trong khi đang test, Champion và Challenger không còn được test trong cùng điều kiện nữa. Phải lock policy trong suốt C/C period, hoặc restart test.

Selection bias trong routing. Nếu loan officers biết đơn nào đang chạy Challenger và đơn nào đang chạy Champion, họ có thể (vô tình) xử lý khác nhau. C/C nên blind với người xử lý hồ sơ.

Không đủ volume cho statistical significance. Một C/C 95/5 split với 500 đơn/tháng có nghĩa là chỉ 25 đơn vào Challenger mỗi tháng. 3 tháng = 75 đơn. Không đủ để kết luận bất cứ điều gì. Tính sample size requirement trước khi commit vào split ratio.

Code thực tế: Tính sample size và kiểm tra kết quả C/C

python
import math
from scipy.stats import proportions_ztest, norm

def required_sample_size(
    p_champion: float,
    p_challenger: float,
    alpha: float = 0.05,
    power: float = 0.80
) -> int:
    """
    Tính số lượng application tối thiểu cho mỗi arm của C/C test.
    p_champion  : bad rate kỳ vọng của Champion (baseline)
    p_challenger: bad rate kỳ vọng của Challenger (alternative)
    """
    z_alpha = norm.ppf(1 - alpha / 2)   # two-sided
    z_beta  = norm.ppf(power)
    p_bar   = (p_champion + p_challenger) / 2

    numerator   = (z_alpha * math.sqrt(2 * p_bar * (1 - p_bar))
                   + z_beta * math.sqrt(p_champion * (1 - p_champion)
                                        + p_challenger * (1 - p_challenger))) ** 2
    denominator = (p_champion - p_challenger) ** 2
    return math.ceil(numerator / denominator)

#  dụ: Champion bad rate 8%, Challenger kỳ vọng giảm xuống 6.5%
n_per_arm = required_sample_size(p_champion=0.08, p_challenger=0.065)
print(f"Mỗi arm cần: {n_per_arm} applications")
#  ~1,024 applications per arm; với 95/5 split: Challenger arm cần ~21,000 total/month

# Sau khi  outcome  kiểm tra statistical significance
champion_bad,  champion_n  = 192, 2400   # 8.0% bad rate
challenger_bad, challenger_n = 52,  800   # 6.5% bad rate

stat, pvalue = proportions_ztest(
    count=[champion_bad, challenger_bad],
    nobs=[champion_n,    challenger_n],
    alternative='larger'   # H1: Champion bad rate > Challenger bad rate
)

print(f"z-statistic: {stat:.3f}")
print(f"p-value    : {pvalue:.4f}")
print("Conclusion :", "Challenger significantly better ✅" if pvalue < 0.05 else "Not conclusive ⚠️")

Giá trị governance

C/C không chỉ là kỹ thuật — nó là ngôn ngữ của risk governance.

Risk committee không muốn nghe "model mới tốt hơn theo thuật toán." Họ muốn nghe "model mới đã chứng minh tốt hơn trên 2,400 đơn thực trong 4 tháng, với Gini cao hơn 3.2pt và DPD30 thấp hơn 0.8%, với statistical significance p < 0.05."

Câu sau có thể đưa vào meeting minutes, vào model validation report, vào regulatory submission. Câu trước thì không.

C/C tạo ra audit trail cho mọi model transition: ai approve, khi nào, trên evidence gì. Đó là thứ bảo vệ bạn 2 năm sau khi model đó có vấn đề và ai đó hỏi "tại sao anh deploy cái này?"


Pitfalls phổ biến

Define success criteria sau khi thấy kết quả. Đây là dạng p-hacking trong credit modeling. "Model mới có approval rate cao hơn 2%, vậy ta dùng approval rate làm primary metric." Không. Primary metric phải được định nghĩa trước khi split.

Test window quá ngắn. 30 ngày không phải C/C — đó là smoke test. Credit outcome cần thời gian để trưởng thành.

Không document assumptions. Sau 6 tháng, không ai nhớ tại sao split là 95/5 thay vì 90/10, tại sao dùng DPD30 thay vì DPD60. Document everything.

Celebrate uplift mà bỏ qua cost. Challenger có Gini cao hơn 2pt nhưng approval rate thấp hơn 3%. Tùy vào margin của ngân hàng, revenue loss từ 3% approval rate có thể outweigh benefit của 2pt Gini. Luôn tính full business case.


Takeaway

Champion-Challenger không phải best practice tùy chọn cho các team nào muốn "làm kỹ." Nó là yêu cầu governance cho bất kỳ ngân hàng nào có risk committee và model validation function.

Nếu bạn không có C/C, bạn không có bằng chứng — bạn chỉ có niềm tin. Và niềm tin không phải là thứ risk committee chấp nhận khi NPL tăng và ai đó hỏi "tại sao anh deploy model đó?"


Bài liên quan / Related posts