返回文章列表

機器學習驅動的信用貸款評估系統:多維度風險分析與智慧決策模型

深入探討信用貸款評估的多維度分析方法,從信用評分、收入水準、就業穩定性到債務比率的綜合評估,實作完整的資料分析流程與視覺化系統,建構決策樹與預測模型,提供金融機構優化信貸審核流程的實務指南。

資料分析 機器學習 金融科技

信用貸款評估是金融機構面臨的核心業務挑戰之一,涉及對借款人還款能力與意願的綜合判斷。傳統的信貸審核往往依賴固定的評分規則與人工判斷,這種方法雖然直觀但難以處理大量申請案件,更無法有效捕捉借款人特徵之間的複雜交互作用。現代資料分析技術與機器學習演算法的引入,使得金融機構能夠從歷史貸款資料中學習違約模式,建構更精準的風險預測模型。然而實務資料分析發現,信用評分與收入這兩個最常用的評估維度並非決定貸款批准的唯一因素,高信用評分的申請人可能因債務負擔過重而被拒絕,低信用評分者也可能因穩定的高收入與良好的就業記錄獲得批准。這種多維度的決策邏輯反映了信貸風險評估的本質複雜性,需要綜合考量借款人的財務狀況、信用歷史、就業穩定性、債務比率以及貸款用途等多個面向,才能做出合理的信貸決策。

信用貸款申請資料的深度探索性分析

探索性資料分析是理解信貸資料特性的首要步驟,透過統計摘要與視覺化技術揭示資料中隱藏的模式與關聯。信用貸款申請資料集通常包含申請人的基本資訊如年齡、性別、教育程度,財務資訊如年收入、月收入、現有債務金額,信用資訊如信用評分、信用歷史長度、近期信用查詢次數,就業資訊如職業類別、就業年資、雇主類型,以及貸款資訊如申請金額、貸款期限、貸款用途與最終的批准決策。完整的資料探索需要從單變量分析開始,檢視每個特徵的分佈特性、中心趨勢、離散程度以及異常值分佈。信用評分的分佈通常呈現右偏常態分佈,大部分申請人集中在中等分數範圍,極高分與極低分的比例較少。收入分佈則呈現明顯的右偏特性,少數高收入者拉高平均值使其遠高於中位數。

雙變量分析探討特徵之間以及特徵與目標變數之間的關係。信用評分與貸款批准率之間通常呈現正相關,但這種關係並非線性,在某些分數區間批准率的提升速度更快。收入與批准率的關係同樣複雜,低收入區間批准率隨收入增加快速上升,但達到某個閾值後批准率的邊際增益遞減。債務收入比對批准決策有顯著影響,當既有債務支付占收入的比例超過40%時,批准率急劇下降。就業年資反映還款穩定性,就業超過三年的申請人批准率明顯高於就業未滿一年者。貸款金額與收入的比例同樣關鍵,申請過高金額的貸款即使信用評分優良也可能被拒絕。類別型特徵如房屋所有權狀態、職業類別、貸款用途都展現出與批准率的關聯,擁有房產的申請人批准率較高,從事專業技術工作者相較於臨時工有更高批准率,用於債務整合的貸款相較於投機性質的貸款更容易獲批。

# 信用貸款申請資料探索性分析系統
# 完整的資料載入、統計分析、視覺化與洞察提取流程

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from scipy.stats import chi2_contingency
import warnings
warnings.filterwarnings('ignore')

# 設定繁體中文顯示
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False

class LoanDataExplorer:
    """
    貸款資料探索分析器
    提供全面的探索性資料分析功能
    """
    
    def __init__(self):
        """初始化探索分析器"""
        self.data = None
        self.numeric_features = []
        self.categorical_features = []
        self.target = 'loan_approved'
        
    def generate_sample_data(self, n_samples=500):
        """
        生成範例信用貸款申請資料
        模擬真實的貸款申請場景
        
        參數:
            n_samples: 樣本數量
            
        回傳:
            data: 生成的DataFrame
        """
        np.random.seed(42)
        
        # 生成申請人ID
        applicant_ids = np.arange(1, n_samples + 1)
        
        # 生成信用評分(300-850,偏向中高分)
        credit_scores = np.random.beta(5, 2, n_samples) * 550 + 300
        credit_scores = credit_scores.astype(int)
        
        # 生成年收入(對數常態分佈,30000-150000)
        incomes = np.random.lognormal(mean=11.2, sigma=0.6, size=n_samples)
        incomes = np.clip(incomes, 30000, 150000).astype(int)
        
        # 生成申請貸款金額(與收入相關,有隨機性)
        loan_amounts = incomes * np.random.uniform(0.5, 3.5, n_samples)
        loan_amounts = loan_amounts.astype(int)
        
        # 生成現有債務金額
        existing_debt = incomes * np.random.uniform(0.1, 0.6, n_samples)
        existing_debt = existing_debt.astype(int)
        
        # 計算債務收入比
        debt_to_income = existing_debt / incomes
        
        # 生成就業年資(指數分佈,0-30年)
        employment_years = np.random.exponential(scale=6, size=n_samples)
        employment_years = np.clip(employment_years, 0, 30).astype(int)
        
        # 生成年齡(常態分佈,23-65歲)
        ages = np.random.normal(loc=40, scale=12, size=n_samples)
        ages = np.clip(ages, 23, 65).astype(int)
        
        # 生成類別型特徵
        education_levels = np.random.choice(
            ['高中', '專科', '大學', '研究所'],
            size=n_samples,
            p=[0.2, 0.25, 0.4, 0.15]
        )
        
        home_ownership = np.random.choice(
            ['租賃', '自有', '抵押'],
            size=n_samples,
            p=[0.35, 0.35, 0.30]
        )
        
        employment_type = np.random.choice(
            ['全職', '兼職', '自僱', '約聘'],
            size=n_samples,
            p=[0.6, 0.15, 0.15, 0.1]
        )
        
        loan_purpose = np.random.choice(
            ['債務整合', '購車', '房屋裝修', '創業', '教育', '醫療', '其他'],
            size=n_samples,
            p=[0.3, 0.2, 0.15, 0.1, 0.1, 0.1, 0.05]
        )
        
        # 建構批准決策的多因素模型
        # 標準化各個因素到0-1範圍
        credit_normalized = (credit_scores - 300) / 550
        income_normalized = (incomes - 30000) / 120000
        debt_normalized = 1 - debt_to_income  # 反轉,低債務是好的
        employment_normalized = employment_years / 30
        age_normalized = (ages - 23) / 42
        
        # 教育程度評分
        education_score = pd.Series(education_levels).map({
            '高中': 0.3, '專科': 0.5, '大學': 0.7, '研究所': 0.9
        }).values
        
        # 房屋所有權評分
        home_score = pd.Series(home_ownership).map({
            '租賃': 0.3, '抵押': 0.6, '自有': 0.9
        }).values
        
        # 就業類型評分
        employment_score = pd.Series(employment_type).map({
            '兼職': 0.3, '約聘': 0.5, '自僱': 0.6, '全職': 0.8
        }).values
        
        # 貸款用途評分(穩定用途分數較高)
        purpose_score = pd.Series(loan_purpose).map({
            '醫療': 0.5, '其他': 0.5, '創業': 0.6, '教育': 0.7,
            '購車': 0.7, '房屋裝修': 0.8, '債務整合': 0.9
        }).values
        
        # 貸款收入比評分(申請金額相對收入的合理性)
        loan_to_income = loan_amounts / incomes
        loan_ratio_score = np.where(
            loan_to_income < 1, 0.9,
            np.where(loan_to_income < 2, 0.7,
            np.where(loan_to_income < 3, 0.4, 0.1))
        )
        
        # 綜合評分(加權平均)
        approval_score = (
            credit_normalized * 0.25 +      # 信用評分權重25%
            income_normalized * 0.15 +      # 收入權重15%
            debt_normalized * 0.20 +        # 債務比率權重20%
            employment_normalized * 0.10 +  # 就業年資權重10%
            age_normalized * 0.05 +         # 年齡權重5%
            education_score * 0.05 +        # 教育程度權重5%
            home_score * 0.05 +             # 房屋所有權權重5%
            employment_score * 0.05 +       # 就業類型權重5%
            purpose_score * 0.05 +          # 貸款用途權重5%
            loan_ratio_score * 0.05         # 貸款比率權重5%
        )
        
        # 加入隨機擾動模擬不確定性
        approval_score += np.random.normal(0, 0.1, n_samples)
        approval_score = np.clip(approval_score, 0, 1)
        
        # 根據評分決定批准結果(使用較高的閾值確保合理的拒絕率)
        loan_approved = (approval_score > 0.55).astype(int)
        
        # 生成貸款狀態描述
        loan_status = ['批准' if approved else '拒絕' 
                      for approved in loan_approved]
        
        # 建立DataFrame
        self.data = pd.DataFrame({
            'applicant_id': applicant_ids,
            'credit_score': credit_scores,
            'income': incomes,
            'loan_amount': loan_amounts,
            'existing_debt': existing_debt,
            'debt_to_income': debt_to_income,
            'employment_years': employment_years,
            'age': ages,
            'education': education_levels,
            'home_ownership': home_ownership,
            'employment_type': employment_type,
            'loan_purpose': loan_purpose,
            'loan_to_income': loan_to_income,
            'loan_status': loan_status,
            'loan_approved': loan_approved,
            'approval_score': approval_score
        })
        
        # 識別特徵類型
        self.numeric_features = [
            'credit_score', 'income', 'loan_amount', 'existing_debt',
            'debt_to_income', 'employment_years', 'age', 'loan_to_income'
        ]
        
        self.categorical_features = [
            'education', 'home_ownership', 'employment_type', 'loan_purpose'
        ]
        
        approval_rate = loan_approved.mean()
        print(f"成功生成 {n_samples} 筆貸款申請資料")
        print(f"整體批准率: {approval_rate:.2%}")
        print(f"批准案件: {loan_approved.sum()} 筆")
        print(f"拒絕案件: {(1-loan_approved).sum()} 筆")
        
        return self.data
    
    def univariate_analysis(self):
        """
        單變量分析
        分析每個特徵的分佈特性
        """
        if self.data is None:
            print("錯誤: 尚未載入資料")
            return
        
        print("\n" + "="*70)
        print("單變量分析")
        print("="*70)
        
        # 數值型特徵分析
        print("\n【數值型特徵統計摘要】")
        stats_summary = self.data[self.numeric_features].describe()
        print(stats_summary)
        
        # 計算偏度和峰度
        print("\n【分佈形態指標】")
        print(f"{'特徵':20s} {'偏度':>10s} {'峰度':>10s}")
        print("-" * 42)
        
        for feature in self.numeric_features:
            skewness = self.data[feature].skew()
            kurtosis = self.data[feature].kurtosis()
            print(f"{feature:20s} {skewness:>10.3f} {kurtosis:>10.3f}")
        
        # 類別型特徵分析
        print("\n【類別型特徵分佈】")
        for feature in self.categorical_features:
            print(f"\n{feature}:")
            value_counts = self.data[feature].value_counts()
            value_pcts = self.data[feature].value_counts(normalize=True) * 100
            
            for category in value_counts.index:
                count = value_counts[category]
                pct = value_pcts[category]
                print(f"  {category:15s}: {count:4d} ({pct:5.1f}%)")
    
    def bivariate_analysis(self):
        """
        雙變量分析
        分析特徵與目標變數的關係
        """
        if self.data is None:
            print("錯誤: 尚未載入資料")
            return
        
        print("\n" + "="*70)
        print("雙變量分析:特徵與貸款批准的關係")
        print("="*70)
        
        # 數值型特徵與目標變數的關係
        print("\n【數值型特徵的批准率分析】")
        
        for feature in self.numeric_features:
            # 計算不同分位數的批准率
            quartiles = pd.qcut(
                self.data[feature], 
                q=4, 
                labels=['Q1(最低25%)', 'Q2', 'Q3', 'Q4(最高25%)'],
                duplicates='drop'
            )
            
            approval_by_quartile = self.data.groupby(quartiles)[self.target].agg([
                ('批准數', 'sum'),
                ('總數', 'count'),
                ('批准率', 'mean')
            ])
            
            print(f"\n{feature}:")
            print(approval_by_quartile.to_string())
            
            # 計算相關係數
            correlation = self.data[feature].corr(self.data[self.target])
            print(f"與批准決策的相關係數: {correlation:.4f}")
        
        # 類別型特徵與目標變數的關係
        print("\n【類別型特徵的批准率分析】")
        
        for feature in self.categorical_features:
            approval_by_category = self.data.groupby(feature)[self.target].agg([
                ('批准數', 'sum'),
                ('總數', 'count'),
                ('批准率', lambda x: f"{x.mean():.1%}")
            ])
            
            print(f"\n{feature}:")
            print(approval_by_category.to_string())
            
            # 卡方檢定評估類別特徵與批准決策的關聯性
            contingency_table = pd.crosstab(
                self.data[feature], 
                self.data[self.target]
            )
            chi2, p_value, dof, expected = chi2_contingency(contingency_table)
            
            print(f"卡方統計量: {chi2:.4f}, p-value: {p_value:.4f}")
            if p_value < 0.05:
                print("結論: 該特徵與批准決策有顯著關聯")
            else:
                print("結論: 該特徵與批准決策無顯著關聯")
    
    def visualize_key_relationships(self):
        """
        視覺化關鍵關係
        繪製最重要的特徵與批准決策的關係圖
        """
        if self.data is None:
            print("錯誤: 尚未載入資料")
            return
        
        print("\n生成視覺化圖表...")
        
        # 設定圖表樣式
        sns.set_style("whitegrid")
        
        # 1. 信用評分與批准率的關係
        fig, axes = plt.subplots(2, 2, figsize=(16, 12))
        
        # 子圖1: 信用評分分佈(按批准狀態)
        ax1 = axes[0, 0]
        approved = self.data[self.data[self.target] == 1]['credit_score']
        rejected = self.data[self.data[self.target] == 0]['credit_score']
        
        ax1.hist(approved, bins=30, alpha=0.6, label='批准', color='green', edgecolor='black')
        ax1.hist(rejected, bins=30, alpha=0.6, label='拒絕', color='red', edgecolor='black')
        ax1.set_xlabel('信用評分')
        ax1.set_ylabel('頻率')
        ax1.set_title('信用評分分佈(按批准狀態)', fontsize=14, fontweight='bold')
        ax1.legend()
        ax1.grid(alpha=0.3)
        
        # 子圖2: 收入與批准率的關係
        ax2 = axes[0, 1]
        income_bins = pd.cut(self.data['income'], bins=10)
        approval_by_income = self.data.groupby(income_bins)[self.target].mean()
        
        x_labels = [f"{int(interval.left/1000)}-{int(interval.right/1000)}K" 
                   for interval in approval_by_income.index]
        
        ax2.bar(range(len(approval_by_income)), approval_by_income.values, 
               color='steelblue', edgecolor='black')
        ax2.set_xticks(range(len(approval_by_income)))
        ax2.set_xticklabels(x_labels, rotation=45, ha='right')
        ax2.set_xlabel('年收入區間')
        ax2.set_ylabel('批准率')
        ax2.set_title('年收入與批准率的關係', fontsize=14, fontweight='bold')
        ax2.set_ylim([0, 1])
        ax2.grid(axis='y', alpha=0.3)
        
        # 在長條圖上顯示數值
        for i, v in enumerate(approval_by_income.values):
            ax2.text(i, v + 0.02, f'{v:.1%}', ha='center', va='bottom')
        
        # 子圖3: 債務收入比與批准率的關係
        ax3 = axes[1, 0]
        debt_bins = pd.cut(self.data['debt_to_income'], bins=10)
        approval_by_debt = self.data.groupby(debt_bins)[self.target].mean()
        
        x_labels = [f"{interval.left:.2f}-{interval.right:.2f}" 
                   for interval in approval_by_debt.index]
        
        ax3.plot(range(len(approval_by_debt)), approval_by_debt.values, 
                marker='o', linewidth=2, markersize=8, color='darkred')
        ax3.set_xticks(range(len(approval_by_debt)))
        ax3.set_xticklabels(x_labels, rotation=45, ha='right')
        ax3.set_xlabel('債務收入比')
        ax3.set_ylabel('批准率')
        ax3.set_title('債務收入比與批准率的關係', fontsize=14, fontweight='bold')
        ax3.set_ylim([0, 1])
        ax3.grid(alpha=0.3)
        
        # 子圖4: 類別特徵的批准率比較
        ax4 = axes[1, 1]
        
        # 計算每個類別特徵的平均批准率差異
        category_impact = {}
        for feature in self.categorical_features:
            approval_rates = self.data.groupby(feature)[self.target].mean()
            category_impact[feature] = approval_rates.max() - approval_rates.min()
        
        sorted_features = sorted(category_impact.items(), 
                               key=lambda x: x[1], reverse=True)
        
        features = [item[0] for item in sorted_features]
        impacts = [item[1] for item in sorted_features]
        
        ax4.barh(range(len(features)), impacts, color='coral', edgecolor='black')
        ax4.set_yticks(range(len(features)))
        ax4.set_yticklabels(features)
        ax4.set_xlabel('批准率差異(最大-最小)')
        ax4.set_title('類別特徵對批准率的影響', fontsize=14, fontweight='bold')
        ax4.grid(axis='x', alpha=0.3)
        
        # 在長條圖上顯示數值
        for i, v in enumerate(impacts):
            ax4.text(v + 0.01, i, f'{v:.1%}', va='center')
        
        plt.tight_layout()
        plt.show()
    
    def correlation_heatmap(self):
        """
        繪製數值型特徵的相關性熱圖
        """
        if self.data is None:
            print("錯誤: 尚未載入資料")
            return
        
        print("\n生成相關性熱圖...")
        
        # 計算相關係數矩陣
        numeric_data = self.data[self.numeric_features + [self.target]]
        correlation_matrix = numeric_data.corr()
        
        # 繪製熱圖
        plt.figure(figsize=(12, 10))
        sns.heatmap(
            correlation_matrix,
            annot=True,
            fmt='.3f',
            cmap='RdYlGn',
            center=0,
            square=True,
            linewidths=1,
            cbar_kws={'label': '相關係數'}
        )
        plt.title('數值型特徵相關性熱圖', fontsize=16, fontweight='bold', pad=20)
        plt.tight_layout()
        plt.show()
        
        # 輸出與批准決策相關性最高的特徵
        target_corr = correlation_matrix[self.target].sort_values(ascending=False)
        
        print("\n與批准決策相關性排名:")
        print("="*50)
        for feature, corr in target_corr.items():
            if feature != self.target:
                print(f"{feature:25s}: {corr:>7.4f}")
    
    def segment_analysis(self):
        """
        分群分析
        識別高風險與低風險申請人群組
        """
        if self.data is None:
            print("錯誤: 尚未載入資料")
            return
        
        print("\n" + "="*70)
        print("分群分析")
        print("="*70)
        
        # 定義風險分群規則
        conditions = [
            # 低風險:高信用評分、低債務比率、穩定就業
            (self.data['credit_score'] >= 700) & 
            (self.data['debt_to_income'] <= 0.3) & 
            (self.data['employment_years'] >= 3),
            
            # 中低風險
            (self.data['credit_score'] >= 650) & 
            (self.data['debt_to_income'] <= 0.4) & 
            (self.data['employment_years'] >= 1),
            
            # 中高風險
            (self.data['credit_score'] >= 550) & 
            (self.data['debt_to_income'] <= 0.5),
        ]
        
        choices = ['低風險', '中低風險', '中高風險']
        
        self.data['risk_segment'] = np.select(conditions, choices, default='高風險')
        
        # 分析各風險群組的批准率
        segment_analysis = self.data.groupby('risk_segment').agg({
            'applicant_id': 'count',
            'loan_approved': ['sum', 'mean'],
            'credit_score': 'mean',
            'income': 'mean',
            'debt_to_income': 'mean'
        }).round(2)
        
        segment_analysis.columns = ['申請人數', '批准數', '批准率', 
                                   '平均信用評分', '平均收入', '平均債務比率']
        
        # 按風險等級排序
        risk_order = ['低風險', '中低風險', '中高風險', '高風險']
        segment_analysis = segment_analysis.reindex(risk_order)
        
        print("\n各風險群組分析:")
        print(segment_analysis.to_string())
        
        # 視覺化風險分群
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
        
        # 子圖1: 各風險群組的申請人數分佈
        segment_counts = self.data['risk_segment'].value_counts()
        segment_counts = segment_counts.reindex(risk_order)
        
        colors = ['green', 'yellowgreen', 'orange', 'red']
        ax1.pie(segment_counts.values, labels=segment_counts.index, 
               autopct='%1.1f%%', colors=colors, startangle=90)
        ax1.set_title('風險群組分佈', fontsize=14, fontweight='bold')
        
        # 子圖2: 各風險群組的批准率
        approval_by_segment = self.data.groupby('risk_segment')[self.target].mean()
        approval_by_segment = approval_by_segment.reindex(risk_order)
        
        bars = ax2.bar(range(len(approval_by_segment)), 
                      approval_by_segment.values,
                      color=colors, edgecolor='black')
        ax2.set_xticks(range(len(approval_by_segment)))
        ax2.set_xticklabels(approval_by_segment.index)
        ax2.set_ylabel('批准率')
        ax2.set_title('各風險群組批准率', fontsize=14, fontweight='bold')
        ax2.set_ylim([0, 1])
        ax2.grid(axis='y', alpha=0.3)
        
        # 在長條圖上顯示數值
        for bar, value in zip(bars, approval_by_segment.values):
            height = bar.get_height()
            ax2.text(bar.get_x() + bar.get_width()/2., height + 0.02,
                    f'{value:.1%}', ha='center', va='bottom', fontweight='bold')
        
        plt.tight_layout()
        plt.show()

# 主程式執行
if __name__ == "__main__":
    # 初始化探索分析器
    explorer = LoanDataExplorer()
    
    # 生成範例資料
    print("生成信用貸款申請範例資料...")
    data = explorer.generate_sample_data(n_samples=800)
    
    # 顯示前幾筆資料
    print("\n前10筆資料範例:")
    print(data[['applicant_id', 'credit_score', 'income', 'loan_amount',
               'debt_to_income', 'loan_status']].head(10).to_string())
    
    # 執行單變量分析
    explorer.univariate_analysis()
    
    # 執行雙變量分析
    explorer.bivariate_analysis()
    
    # 視覺化關鍵關係
    explorer.visualize_key_relationships()
    
    # 繪製相關性熱圖
    explorer.correlation_heatmap()
    
    # 執行分群分析
    explorer.segment_analysis()
    
    print("\n探索性資料分析完成!")

這段完整的探索性資料分析系統展示了如何系統性地理解信用貸款申請資料。LoanDataExplorer類別實作了從資料生成到深度分析的完整流程,資料生成功能模擬真實的貸款申請場景,綜合考量信用評分、收入、債務、就業、教育、房屋所有權等多個維度,使用加權評分模型決定批准結果以反映真實決策的複雜性。單變量分析提供每個特徵的統計摘要,包含中心趨勢、離散程度、分佈形態等描述性統計量,偏度與峰度指標揭示分佈的對稱性與尾部特性。雙變量分析深入探討特徵與批准決策的關係,對數值型特徵採用分位數分析觀察批准率在不同數值區間的變化模式,相關係數量化線性關聯強度。對類別型特徵則計算各類別的批准率差異並使用卡方檢定評估統計顯著性。視覺化功能透過多種圖表類型呈現關鍵洞察,直方圖比較批准與拒絕群組在信用評分上的分佈差異,長條圖展示收入區間與批准率的關係,折線圖揭示債務收入比對批准率的影響趨勢。相關性熱圖使用顏色編碼直觀呈現特徵間的相關強度,協助識別多重共線性問題。分群分析根據風險特徵組合將申請人分為低、中低、中高、高風險四個群組,分析各群組的批准率差異與特徵分佈,為風險定價與審核策略提供依據。

決策樹模型的建構與信貸決策規則提取

決策樹是信用評分領域最受歡迎的模型之一,因其決策過程透明易懂且能夠自動發現特徵間的交互作用。決策樹透過遞迴分割特徵空間將申請人分群,每次分割選擇能最大化群組純度提升的特徵與分割點。群組純度通常使用基尼不純度或資訊熵來衡量,純度越高代表群組內的申請人批准狀態越一致。模型訓練過程中需要謹慎調整樹的深度與最小樣本數以防止過度擬合,過深的樹會記憶訓練資料的細節而失去泛化能力。剪枝技術透過移除對預測貢獻小的分支簡化模型提升可解釋性。成本複雜度剪枝在樹的複雜度與預測誤差間取得平衡,根據驗證集效能選擇最佳的複雜度參數。

決策樹的一大優勢在於能夠提取人類可理解的決策規則,每條從根節點到葉節點的路徑對應一個決策規則。例如規則可能是如果信用評分大於700且債務收入比小於0.3則批准貸款,這種規則能夠直接應用於實務審核流程並向申請人說明決策依據。特徵重要性分析揭示哪些因素對決策影響最大,重要性通常根據特徵被用於分割的次數與分割帶來的純度提升來計算。視覺化決策樹的完整結構協助理解模型的決策邏輯,雖然完整樹可能過於龐大,但可以展示關鍵的頂層分割以提供整體直覺。決策邊界的視覺化展示模型如何在特徵空間中劃分批准與拒絕區域,對於理解模型行為特別有幫助。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

title 信用貸款決策樹分析流程

package "資料準備模組" {
  [原始申請資料] as RAW_DATA
  [資料清洗] as CLEAN
  [特徵工程] as FEATURE_ENG
  [訓練測試分割] as SPLIT
}

package "模型訓練模組" {
  [決策樹訓練] as TRAIN_TREE
  [超參數調整] as TUNE
  [模型剪枝] as PRUNE
  [交叉驗證] as CV
}

package "模型評估模組" {
  [效能指標計算] as METRICS
  [混淆矩陣分析] as CONFUSION
  [ROC曲線繪製] as ROC
  [特徵重要性] as IMPORTANCE
}

package "規則提取模組" {
  [決策路徑提取] as PATH_EXTRACT
  [規則簡化] as SIMPLIFY
  [規則驗證] as VALIDATE
  [規則部署] as DEPLOY
}

database "模型儲存庫" as MODEL_REPO {
  [訓練好的模型]
  [決策規則集]
  [效能報告]
}

actor "資料科學家" as DS
actor "業務分析師" as BA
actor "信貸審核員" as LOAN_OFFICER

RAW_DATA --> CLEAN : 資料載入
CLEAN --> FEATURE_ENG : 乾淨資料
FEATURE_ENG --> SPLIT : 工程化特徵

SPLIT --> TRAIN_TREE : 訓練集
SPLIT --> METRICS : 測試集

TRAIN_TREE --> TUNE : 基礎模型
TUNE --> PRUNE : 調整後模型
PRUNE --> CV : 剪枝後模型

CV --> METRICS : 最終模型
METRICS --> CONFUSION : 預測結果
CONFUSION --> ROC : 評估指標
ROC --> IMPORTANCE : 效能報告

IMPORTANCE --> PATH_EXTRACT : 特徵分析
PATH_EXTRACT --> SIMPLIFY : 原始規則
SIMPLIFY --> VALIDATE : 簡化規則
VALIDATE --> DEPLOY : 驗證規則

TRAIN_TREE --> MODEL_REPO : 儲存模型
IMPORTANCE --> MODEL_REPO : 儲存特徵
DEPLOY --> MODEL_REPO : 儲存規則

DS --> TRAIN_TREE
DS --> TUNE
BA --> SIMPLIFY
BA --> VALIDATE
LOAN_OFFICER --> DEPLOY

note right of FEATURE_ENG
  特徵工程包含:
  - 衍生特徵建立
  - 特徵標準化
  - 類別編碼
  - 缺失值處理
end note

note right of TUNE
  超參數調整:
  - 最大深度
  - 最小分割樣本數
  - 最小葉節點樣本數
  - 分割標準(基尼/熵)
end note

note right of PATH_EXTRACT
  規則提取範例:
  IF 信用評分 > 700
  AND 債務比率 < 0.3
  THEN 批准貸款
end note

@enduml

這張流程圖完整呈現決策樹模型在信用貸款評估中的應用架構。資料準備模組從原始申請資料開始,執行資料清洗處理遺失值、異常值與資料不一致性問題。特徵工程階段建構衍生特徵如債務收入比、貸款收入比等風險指標,對數值特徵進行標準化處理,將類別特徵轉換為數值表示。訓練測試分割採用分層採樣確保兩個集合中的批准率比例一致,通常保留20-30%資料作為測試集評估模型的泛化效能。

模型訓練模組實作決策樹的訓練與優化流程。決策樹訓練使用CART演算法遞迴分割資料,在每個節點選擇能最大化資訊增益或基尼不純度減少的特徵與分割點。超參數調整透過網格搜尋或隨機搜尋探索不同參數組合,關鍵參數包含樹的最大深度控制模型複雜度,最小分割樣本數要求節點包含足夠樣本才能繼續分割,最小葉節點樣本數確保預測基於充分資料,分割標準選擇基尼不純度或資訊熵作為分割品質度量。模型剪枝移除對驗證集效能貢獻小的分支,成本複雜度剪枝在樹的大小與預測誤差間取得平衡。交叉驗證評估模型在不同資料子集上的穩定性,使用5折或10折交叉驗證提供更可靠的效能估計。

模型評估模組全面檢視決策樹的預測能力。效能指標計算包含準確率衡量整體正確率,精確率評估預測為批准中真正應批准的比例,召回率評估實際應批准中被正確識別的比例,F1分數平衡精確率與召回率。混淆矩陣分析提供四種預測結果的詳細數量,真陽性代表正確批准,真陰性代表正確拒絕,假陽性代表誤批可能導致壞帳,假陰性代表誤拒損失業務機會。ROC曲線繪製展示在不同判斷閾值下真陽性率與假陽性率的權衡,AUC值量化曲線下面積評估整體區分能力。特徵重要性分析識別對決策影響最大的因素,根據特徵在樹中被用於分割的總次數與帶來的純度提升計算重要性分數。

規則提取模組將決策樹轉換為可解釋的業務規則。決策路徑提取追蹤從根節點到每個葉節點的完整路徑,每條路徑對應一個IF-THEN規則描述導致特定決策的條件組合。規則簡化移除冗餘條件與合併相似規則,減少規則集的複雜度同時保持預測準確性。規則驗證在獨立測試集上檢驗規則的準確性與覆蓋率,確保規則在新資料上依然有效。規則部署將驗證通過的規則整合至信貸審核系統,規則引擎根據申請人資料自動執行規則並給出初步決策建議,審核員可以檢視觸發的具體規則理解決策依據。模型儲存庫保存訓練好的模型物件、提取的決策規則集以及詳細的效能評估報告,支援模型版本管理與審計追蹤。資料科學家負責模型訓練與調優,業務分析師參與規則簡化與驗證確保規則符合業務邏輯,信貸審核員使用部署的規則協助日常審核工作並提供規則改進建議。

信用貸款評估的複雜性源於多個因素的交互作用與非線性關係,單純依賴信用評分或收入水準無法全面評估借款人的違約風險。本文透過完整的探索性資料分析揭示了影響貸款決策的關鍵因素,信用評分反映歷史信用表現但無法捕捉當前財務壓力,收入水準代表還款能力但需要考慮收入穩定性,債務收入比直接衡量財務負擔是最重要的風險指標之一,就業年資與類型反映收入的持續性與可預測性,教育程度與房屋所有權間接暗示財務管理能力與資產基礎,貸款用途影響資金使用合理性與還款意願。決策樹模型提供了結合這些因素的系統性框架,透過自動學習特徵間的交互作用建構準確的預測模型,更重要的是提取可解釋的決策規則支援實務應用。

金融機構在應用這些技術時需要平衡多個目標,包含預測準確性確保風險控制,模型可解釋性滿足監管要求與客戶溝通需求,處理效率支援大量申請的快速審核,公平性避免對特定群體的系統性歧視。持續的模型監控與更新同樣重要,因為經濟環境變化、政策調整與客戶行為演變都可能影響模型效能。建議金融機構建立完整的模型治理框架,包含定期的效能評估檢視關鍵指標是否維持在可接受範圍,公平性審計確保不同群體獲得平等對待,回測分析比較模型預測與實際違約情況,持續優化根據新資料與業務回饋改進模型。透過系統性的資料分析與機器學習技術應用,金融機構能夠在控制風險的同時提升審核效率並改善客戶體驗,實現可持續的業務增長。