1. 程式人生 > >貸款使用者逾期情況分析

貸款使用者逾期情況分析

目錄

任務描述

實現過程

基本思路

4.2 LR

遇到的問題

參考

More

任務描述

給定金融資料,預測貸款使用者是否會逾期。(status是標籤:0表示未逾期,1表示逾期。)

Misson1 - 構建邏輯迴歸模型進行預測
Misson2 - 構建SVM和決策樹模型進行預測
Misson3 - 構建xgboost和lightgbm模型進行預測
Mission4 - 記錄五個模型關於precision,rescore,f1,auc,roc的評分表格,畫出auc和roc曲線圖
Mission5 - 關於資料型別轉換以及缺失值處理(嘗試不同的填充看效果)以及你能借鑑的資料探索
Mission6

- 使用網格搜尋對模型進行調優並採用五折交叉驗證的方式進行模型評估
Mission7 - 用你目前評分最高的模型作為基準模型,和其他模型進行stacking融合,得到最終模型及評分

實現過程

基本思路

主要分為以下若干步驟:
1)資料集預覽
2)資料預處理:切分X,y;刪除無用特徵;字元型特徵編碼;缺失值填充 等
3)特徵工程
4)模型選擇:lr,svm,dt,xgboost,lightgbm 等
5)模型調參
6)效能評估
7)最終結果

1. 資料集預覽

# 因為資料並非utf-8編碼,要使用gbk編碼讀入,否則出錯
data = pd.read_csv('./data/data.csv', index_col=0, encoding='gbk')

# 觀察資料構成
# data.head()
print(data.shape)    # (4754, 89)

2. 資料預處理

X, y 劃分

# 劃分 X, y
y = data['status']
X = data.drop('status', axis=1)

特徵處理

# 首先剔除一些明顯無用的特徵,如 id_name, custid, trade_no, bank_card_no,
# 這些優點類似一個人的唯一資訊,如果加入模型訓練且對最終模型生效的話,很可能就是出現了過擬合
X.drop(['id_name', 'custid', 'trade_no', 'bank_card_no'], axis=1, inplace=True)

# 數值型變數
X_num = X.select_dtypes('number').copy()
# student_feature
X_num.fillna({'student_feature': 0}, inplace=True)
# 其他數值型變數使用均值代替
X_num.fillna(X_num.mean(), inplace=True)

# 字元型變數
X_str = X.select_dtypes(exclude='number').copy()
X_str_dummy = pd.get_dummies(X_str['reg_preference_for_trad'])

# 合併
X_cl = pd.concat([X_num, X_str_dummy], axis=1, sort=False)
X_cl.shape

3. 特徵工程

4. 模型選擇

4.1 資料及劃分及資料歸一化

# 資料劃分
from sklearn.model_selection import train_test_split
random_state = 1115
X_train, X_test, y_train, y_test = train_test_split(X_cl, y, test_size=0.3, random_state=random_state)

# 歸一化
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train_std = ss.fit_transform(X_train)
X_test_std = ss.transform(X_test)

4.2 LR

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(C=0.05, penalty='l1')
lr.fit(X_train_std, y_train)

4.3 SVM

from sklearn.svm import SVC
# 線性 SVM
linear_svc = SVC(kernel='linear', probability=True)
linear_svc.fit(X_train_std, y_train)
# 多項式 SVM
poly_svc = SVC(kernel='poly', probability=True)
poly_svc.fit(X_train_std, y_train)

4.4 決策樹

from sklearn.tree import DecisionTreeClassifier
# 決策樹
dt = DecisionTreeClassifier(max_depth=8)
dt.fit(X_train_std, y_train)

4.5 Xgboost

from xgboost.sklearn import XGBClassifier
xgb_params = {
    'learning_rate': 0.1,
    'n_estimators': 42,
    'max_depth': 5,
    'min_child_weight': 1,
    'gamma': 0,
    'subsample': 0.8,
    'colsample_bytree': 0.8,
    'objective': 'binary:logistic',
    'nthread': 4,
    'scale_pos_weight': 1,
    'seed': 112
}
xgb_model = XGBClassifier(**xgb_params)

# 訓練
xgb_model.fit(X_train_std, y_train)

4.6 LightGBM

from lightgbm.sklearn import LGBMClassifier
lgb_params  = {
    'learning_rate': 0.1,
    'n_estimators': 42,
    'max_depth': 5,
    'min_child_weight': 1,
    'gamma': 0,
    'subsample': 0.8,
    'colsample_bytree': 0.8,
    'objective': 'binary', # 這裡和 xgb 不一樣
    'nthread': 4,
    'scale_pos_weight': 1,
    'seed': 112
}
lgb_model = LGBMClassifier(**lgb_params) # 迭代次數(n_estimators)已經是超參之一

# 訓練
lgb_model.fit(X_train_std, y_train)

5. 模型調參

針對以上各個模型進行調參。使用 5折交叉驗證,評價標準使用 roc_auc。

# 設定評價標準
scoring = 'roc_auc'  # 評價標準
n_fold = 5  # n折交叉驗證

以下針對各個模型進行網格調參:

# LR
lr_param = {
    'C': [0.05, 0.1, 0.5, 1],
    'penalty': ['l1', 'l2'],
}

lr_grid = GridSearchCV(lr, lr_param, cv=n_fold, scoring=scoring, n_jobs=-1)
lr_grid.fit(X_train_std, y_train)
print(lr_grid.best_score_)  # 最優分數
print(lr_grid.best_params_)  # 最優引數
print(lr_grid.cv_results_)  # 結果

# 把引數重新賦值給原模型
lr.set_params(**lr_grid.best_params_)
lr.fit(X_train_std, y_train)


# 線性SVC 如果一次性設定的引數太多,可能會跑很長時間,這個時候,建議使用貪心的方法,在某個引數調到最優的時候再調另一個引數
linear_svc_param = {
#     'kernel': ['linear', 'poly']
    'C': [0.5, 1, 5],
#     'degree': [2, 3]
}

linear_svc_grid = GridSearchCV(linear_svc, linear_svc_param, cv=n_fold, scoring=scoring, n_jobs=-1)
linear_svc_grid.fit(X_train_std, y_train)
print(linear_svc_grid.best_score_)  # 最優分數
print(linear_svc_grid.best_params_)  # 最優引數

# 把引數重新賦值給原模型
linear_svc.set_params(**linear_svc_grid.best_params_)
linear_svc.fit(X_train_std, y_train)


# 多項式SVC 
poly_svc_param = {
    'C': [0.5, 1, 5],
    'degree': [2, 3]
}

poly_svc_grid = GridSearchCV(poly_svc, poly_svc_param, cv=n_fold, scoring=scoring, n_jobs=-1)
poly_svc_grid.fit(X_train_std, y_train)
print(poly_svc_grid.best_score_)  # 最優分數
print(poly_svc_grid.best_params_)  # 最優引數

# 把引數重新賦值給原模型
poly_svc.set_params(**svc_grid.best_params_)
poly_svc.fit(X_train_std, y_train)


# 決策樹  關於決策樹引數較多,可參考:https://blog.csdn.net/qq_41577045/article/details/79844709
dt_param = {
    'max_depth': [3, 4, 5, 6, 7,],
}

dt_grid = GridSearchCV(dt, dt_param, cv=n_fold, scoring=scoring, n_jobs=-1)
dt_grid.fit(X_train_std, y_train)
print(dt_grid.best_score_)  # 最優分數
print(dt_grid.best_params_)  # 最優引數

# 把引數重新賦值給原模型
dt.set_params(**dt_grid.best_params_)
dt.fit(X_train_std, y_train)

PS:上面調整的均是比較常見的超參,其他引數請參考官方文件。決策樹中涉及引數較多,對不同資料集調節引數不一,詳細可參考 sklearn種決策樹的演算法引數。另外,XGBoost 與 LightGBM 模型比較複雜,調參過程中涉及的步驟較多,可參考另一篇博文:XGBoost 與 LightGBM 調參

6. 效能評估

評估函式程式碼:

from sklearn.metrics import accuracy_score, recall_score, f1_score, roc_auc_score, roc_curve
from matplotlib import pyplot as plt
# 定義評估函式
def model_metrics(clf, X_train, X_test, y_train, y_test):
    # 預測
    y_train_pred = clf.predict(X_train)
    y_test_pred = clf.predict(X_test)
    y_train_pred_proba = clf.predict_proba(X_train)[:, 1]
    y_test_pred_proba = clf.predict_proba(X_test)[:, 1]

    # 評估
    # 準確性
    print('準確性:')
    print('Train:{:.4f}'.format(accuracy_score(y_train, y_train_pred)))
    print('Test:{:.4f}'.format(accuracy_score(y_test, y_test_pred)))

    # 召回率
    print('召回率:')
    print('Train:{:.4f}'.format(recall_score(y_train, y_train_pred)))
    print('Test:{:.4f}'.format(recall_score(y_test, y_test_pred)))
    
    # f1_score
    print('f1_score:')
    print('Train:{:.4f}'.format(f1_score(y_train, y_train_pred)))
    print('Test:{:.4f}'.format(f1_score(y_test, y_test_pred)))
    
    # roc_auc
    print('roc_auc:')
    print('Train:{:.4f}'.format(roc_auc_score(y_train, y_train_pred_proba)))
    print('Test:{:.4f}'.format(roc_auc_score(y_test, y_test_pred_proba)))    
    
    # 描繪 ROC 曲線
    fpr_tr, tpr_tr, _ = roc_curve(y_train, y_train_pred_proba)
    fpr_te, tpr_te, _ = roc_curve(y_test, y_test_pred_proba)

    # KS
    print('KS:')
    print('Train:{:.4f}'.format(max(abs((fpr_tr - tpr_tr)))))
    print('Test:{:.4f}'.format(max(abs((fpr_te - tpr_te)))))

    # 繪圖
    plt.plot(fpr_tr, tpr_tr, 'r-',
             7label="Train:AUC: {:.3f} KS:{:.3f}".format(roc_auc_score(y_train, y_train_pred_proba), 
                                                        max(abs((fpr_tr - tpr_tr)))))
    plt.plot(fpr_te, tpr_te, 'g-',
             label="Test:AUC: {:.3f} KS:{:.3f}".format(roc_auc_score(y_test, y_test_pred_proba),
                                                     max(abs((fpr_tr - tpr_tr)))))
    plt.plot([0, 1], [0, 1], 'd--')
    plt.legend(loc='best')
    plt.title("ROC curse")
    plt.show()

下面是各個模型的評估函式結果:

accuracy recall f1_score ROC_AUC KS ROC曲線

邏輯迴歸

Train:0.7986
Test:0.8031
Train:0.3198
Test:0.3324
Train:0.4444
Test:0.4565
Train:0.4444
Test:0.4565
Train:0.4564
Test:0.4576
線性SVM Train:0.7944
Test:0.7975
Train:0.2542
Test:0.2676
Train:0.3838
Test:0.3967
Train:0.8082
Test:0.7894
Train:0.4796
Test:0.4575
多項式SVM Train:0.8245
Test:0.7687
Train:0.3079
Test:0.1577
Train:0.4691
Test:0.2534
Train:0.9511
Test:0.7172
Train:0.8093
Test:0.3552
決策樹 Train:0.8777
Test:0.7526
Train:0.6539
Test:0.4085
Train:0.7292
Test:0.4510
Train:0.9016
Test:0.6573
Train:0.6550
Test:0.3018
Xgboost Train:0.8798
Test:0.7940
Train:0.5644
Test:0.3690
Train:0.7028
Test:0.4712
Train:0.9525
Test:0.7932
Train:0.7644
Test:0.4342
LightGBM Train:0.8843
Test:0.7996
Train:0.5776
Test:0.3634
Train:0.7154
Test:0.4743
Train:0.9571
Test:0.7991
Train:0.7776
Test:0.4548

7. 模型融合

關於 Stacking 的原理這裡就不細說了,具體參考 stacking 模型融合

為了貫徹調包俠的理念,這裡直接呼叫 mlxtend 庫裡面的 StackingCVClassifier 進行建模,這個庫可以很好地完成對 sklearn 的 stacking。

from mlxtend.classifier import StackingCVClassifier, StackingClassifier

# 構建 Stacking 模型,因為 dt 評分太低了,所以拋棄掉,使用 lr 作為最後的融合模型
s_clf = StackingClassifier(classifiers=[linear_svc, xgb_model, lgb_model], 
                             meta_classifier=lr, use_probas=True, verbose=3)

s_clf.fit(X_train_std, y_train)

下面我們呼叫上面定義好的函式,看一下模型融合之後的結果:

# 評估 Stacking 模型
model_metrics(s_clf, X_train_std, X_test_std, y_train, y_test)

可以看到,進行模型融合之後,結果並不比原來的 xgb 和 lgb 好,也許模型融合對當前題目並不是一個很好的解決方案。

遇到的問題

1. SVM 使用 rbf 核時,分類結果只有一類
2. 進行模型融合後的結果並沒有比原來好

參考

More