Phân tích nguyên nhân sai sót mô hình XGBoost nhị phân bằng SHAP

SHAP (Shapley Additive Explanations) cung cấp cơ chế giải thích cục bộ và toàn cục để xác định các đặc trưng nào và giá trị cụ thể của chúng đã góp phần đẩy dự đoán của mô hình về phía kết quả sai. Dưới đây là quy trình thực tiễn, được thiết kế lại nhằm tối ưu hóa tính khả thi và độ chính xác khi áp dụng cho các trường hợp sai sót trong bài toán phân lớp nhị phân.

Tư duy nền tảng

  • Xác định tập mẫu lỗi: Tập trung vào hai loại sai sót chiến lược — giả dương (False Positive - FP) và giả âm (False Negative - FN). Đây là những mẫu mà mô hình đưa ra quyết định trái ngược với nhãn thật.
  • Tính toán giá trị SHAP: Sử dụng shap.TreeExplainer để sinh giá trị SHAP cho từng đặc trưng trên các mẫu lỗi. Mỗi giá trị phản ánh mức độ thay đổi đầu ra dự đoán so với kỳ vọng toàn cục (expected value), do sự hiện diện của đặc trưng đó.
  • Trích xuất thông tin hành vi sai: Không chỉ xem "đặc trưng nào quan trọng", mà còn kiểm tra mức độ và hướng ảnh hưởng (dương/nhận) tương ứng với giá trị đặc trưng cụ thể — từ đó suy luận logic sai của mô hình.

Cài đặt và tiền xử lý

Đảm bảo các thư viện cần thiết đã được cài đặt:

pip install shap xgboost scikit-learn pandas numpy matplotlib

Tải mô hình và dữ liệu kiểm thử:

import shap
import xgboost as xgb
from sklearn.metrics import classification_report
import pandas as pd
import numpy as np

# Giả sử mô hình đã được huấn luyện dưới dạng XGBClassifier
# model = xgb.XGBClassifier(...)
# model.fit(X_train, y_train)

# Dữ liệu kiểm thử: DataFrame với cột đặc trưng và mảng nhãn
# X_val, y_val = ... 

# Dự đoán xác suất và nhãn nhị phân
y_proba = model.predict_proba(X_val)[:, 1]
y_pred = (y_proba >= 0.5).astype(int)

# Lập chỉ số mẫu lỗi
mask_fp = (y_pred == 1) & (y_val == 0)
mask_fn = (y_pred == 0) & (y_val == 1)
idx_fp = np.where(mask_fp)[0]
idx_fn = np.where(mask_fn)[0]

print(f"Tổng mẫu kiểm thử: {len(X_val)}")
print(f"FP: {len(idx_fp)}, FN: {len(idx_fn)}")

# Trích xuất dữ liệu con
X_fp_subset = X_val.iloc[idx_fp].reset_index(drop=True)
X_fn_subset = X_val.iloc[idx_fn].reset_index(drop=True)

Tính toán giá trị SHAP hiệu quả

Sử dụng TreeExplainer — lựa chọn tối ưu cho XGBoost — và xử lý đầu ra một cách linh hoạt:

# Khởi tạo bộ giải thích
explainer = shap.TreeExplainer(model)

# Tính SHAP cho toàn bộ tập kiểm thử (tối ưu về thời gian)
try:
    # Với phiên bản SHAP mới hơn
    shap_values_full = explainer.shap_values(X_val)
except Exception:
    # Dự phòng cho cấu trúc mô hình hoặc phiên bản cũ
    shap_values_full = explainer(X_val).values

# Lọc giá trị SHAP theo mẫu lỗi
shap_fp = shap_values_full[idx_fp] if len(idx_fp) > 0 else np.array([])
shap_fn = shap_values_full[idx_fn] if len(idx_fn) > 0 else np.array([])

# Lưu ý: Với phân lớp nhị phân, shap_values_full thường là ma trận (n_samples, n_features)
# đại diện cho ảnh hưởng đến lớp dương (label=1)

Phân tích trực quan hóa sâu

1. Giải thích cục bộ (Force Plot)

Hiển thị tác động từng đặc trưng lên một mẫu cụ thể:

if len(shap_fp) > 0:
    i = 0  # Mẫu FP đầu tiên
    shap.force_plot(
        base_value=explainer.expected_value,
        shap_values=shap_fp[i],
        features=X_fp_subset.iloc[i],
        matplotlib=True,
        show=False
    )
    plt.title("Ảnh hưởng đặc trưng lên mẫu FP (dự đoán=1, thực tế=0)")
    plt.tight_layout()
    plt.show()

Cách đọc: Các đặc trưng màu đỏ đẩy dự đoán về lớp 1; xanh lam kéo về lớp 0. Với mẫu FP, hãy tìm các đặc trưng đỏ mạnh bất thường — kiểm tra giá trị thực tế của chúng có nằm ngoài miền phân bố chuẩn hay không (ví dụ: outlier, giá trị cực đại).

2. Tổng quan nhóm (Bar Summary Plot)

Đánh giá mức độ ảnh hưởng trung bình tuyệt đối trên toàn bộ tập FP/FN:

if len(shap_fp) > 0:
    shap.summary_plot(shap_fp, X_fp_subset, plot_type='bar', max_display=10, show=False)
    plt.title("Đặc trưng có ảnh hưởng lớn nhất tới FP (trung bình |SHAP|)")
    plt.tight_layout()
    plt.show()

So sánh biểu đồ FP và FN giúp phát hiện tính bất đối xứng: ví dụ, đặc trưng income có thể là yếu tố gây FP khi ở mức cao, trong khi debt_ratio lại gây FN khi ở mức thấp — gợi ý mô hình chưa học đúng mối quan hệ phi tuyến giữa các ngưỡng.

3. Phân bố ảnh hưởng (Dot Summary Plot)

Kết hợp giá trị đặc trưng (màu sắc) và giá trị SHAP (vị trí ngang):

if len(shap_fn) > 0:
    shap.summary_plot(shap_fn, X_fn_subset, max_display=10, show=False)
    plt.title("Mối liên hệ giữa giá trị đặc trưng và SHAP trên mẫu FN")
    plt.show()

Với FN, các chấm nằm bên trái (SHAP âm) và có màu đỏ đậm cho thấy đặc trưng có giá trị cao nhưng lại kéo dự đoán xuống — dấu hiệu của mối quan hệ nghịch đảo không mong muốn hoặc nhiễu dữ liệu.

4. Đồ thị phụ thuộc (Dependence Plot)

Khám phá mối quan hệ phi tuyến và tương tác giữa hai đặc trưng:

if len(shap_fp) > 0 and 'credit_score' in X_fp_subset.columns:
    shap.dependence_plot(
        'credit_score',
        shap_fp,
        X_fp_subset,
        interaction_index='employment_length',
        show=False
    )
    plt.title("Tác động của credit_score lên FP, tương tác với employment_length")
    plt.show()

Nếu đường cong SHAP tăng mạnh chỉ trong khoảng credit_score ∈ [650, 720], điều này cho thấy mô hình nhạy cảm với một dải giá trị hẹp — nơi dữ liệu huấn luyện có thể thiếu hoặc bị nhiễu.

Hành động dựa trên kết quả phân tích

  • Tối ưu đặc trưng: Áp dụng biến đổi log, chia nhóm (binning), hoặc xây dựng đặc trưng tương tác rõ ràng nếu đồ thị dependence cho thấy hiệu ứng phi tuyến mạnh.
  • Bổ sung dữ liệu có chủ đích: Tập trung thu thập thêm mẫu trong các vùng đặc trưng có mật độ SHAP cao và sai số lớn (ví dụ: khu vực có nhiều chấm đỏ ở phía trái biểu đồ FN).
  • Điều chỉnh siêu tham số: Nếu một đặc trưng chiếm ưu thế quá mức, tăng reg_alpha hoặc giảm colsample_bytree để hạn chế độ phức tạp và tăng tính tổng quát.
  • Điều chỉnh ngưỡng quyết định: Xây dựng ngưỡng riêng cho các phân khúc đặc trưng (ví dụ: dùng ngưỡng 0.7 cho nhóm có loan_amount > 50000) dựa trên phân bố SHAP.
  • Giới hạn logic mô hình: Áp dụng ràng buộc đơn điệu (monotonic constraints) nếu SHAP cho thấy chiều ảnh hưởng trái ngược với kiến thức chuyên môn (ví dụ: age càng cao lại làm giảm xác suất vỡ nợ).

Thẻ: SHAP XGBoost binary-classification feature-importance model-debugging

Đăng vào ngày 6 tháng 10 lúc 15:04