郵箱:dengzy95@163.com 歡迎交流建議
項目簡介
信用評分技術是一種應用統計模型,其作用是對貸款申請人做風險評估分值的方法。在互金公司等各種貸款業務機構中,普遍使用信用評分,對客戶實行打分制,以期對客戶有一個優質與否的評判。評分卡主要分為三類A卡(申請評分卡)、B卡(行為評分卡)、C卡(貸后評分卡)。我們主要討論的是A卡即申請評分卡,用於貸前審批階段對借款申請人的量化評估;
評分卡原理:
申請評分卡是一種統計模型,它可基於對當前申請人的各項資料進行評估並給出一個分數,該評分能定量對申請人的償債能力作出預判。
客戶申請評分卡由一系列特征項組成,每個特征項相當於申請表上的一個問題(例如,年齡、銀行流水、收入等)。每一個特征項都有一系列可能的屬性,相當於每一個問題的一系列可能答案(例如,對於年齡這個問題,答案可能就有30歲以下、30到45等)。在開發評分卡系統模型中,先確定屬性與申請人未來信用表現之間的相互關系,然后給屬性分配適當的分數權重,分配的分數權重要反映這種相互關系。分數權重越大,說明該屬性表示的信用表現越好。一個申請的得分是其屬性分值的簡單求和。如果申請人的信用評分大於等於金融放款機構所設定的界限分數,此申請處於可接受的風險水平並將被批准;低於界限分數的申請人將被拒絕或給予標示以便進一步審查。
數據來源
數據集來自kaggle中GiveMeSomeCredit項目。地址:https://www.kaggle.com/c/GiveMeSomeCredit/data
開發流程
一、導入數據集
二、數據預處理
三、數據探索
四、特征工程
五、建立模型
六、建立評分卡
一、數據集導入
數據集相對來說比較干凈我們可以直接導入數據。
#先加載后續分箱需要用到的包和模塊
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline df = pd.read_csv("E:\python\data\GiveMeSomeCredit\cs-training.csv") df.head()
特征名稱比較閱讀起來比較困難,讓我們重命名為中文形式。
states={"Unnamed: 0":"用戶ID", "SeriousDlqin2yrs":"好壞客戶", "RevolvingUtilizationOfUnsecuredLines":"可用額度比值", # "age":"年齡", "NumberOfTime30-59DaysPastDueNotWorse":"逾期30-59天筆數", "DebtRatio":"負債率", "MonthlyIncome":"月收入", "NumberOfOpenCreditLinesAndLoans":"信貸數量", "NumberOfTimes90DaysLate":"逾期90天筆數", "NumberRealEstateLoansOrLines":"固定資產貸款量", "NumberOfTime60-89DaysPastDueNotWorse":"逾期60-89天筆數", "NumberOfDependents":"家屬數量"} df.rename(columns=states,inplace=True) df.head()
二、數據預處理
2.1查看數據信息
df.info()
可以看出數據類型為浮點數和整數形式,樣本總量在15000其中月收入和家屬數量特征中有缺失數據。
#計算特征的缺失比例
round(df.isnull().sum()/df.好壞客戶.count(),3)
2.2數據中‘月收入’的缺失值過多,我們利用均值來進行缺失值的填補工作。
對於缺失值較少的‘家屬數量’我們可以直接刪除缺失值。及對數據集進行去重處理。
df = df.fillna({'月收入':df['月收入'].mean()})
df1 = df.dropna()
df1 = df.drop_duplicates()#刪除重復項 df.info()
2.3異常值檢測及處理
利用箱型圖對特征進行可視化來檢測異常數據。
x4=df1["逾期30-59天筆數"] x5=df1["逾期60-89天筆數"] x6=df1["逾期90天筆數"] fig=plt.figure(3) ax=fig.add_subplot(111) ax.boxplot([x4,x5,x6]) ax.set_xticklabels(["逾期30-59天筆數","逾期60-89天筆數","逾期90天筆數"])
通過以上特征可視化我們可以對明顯偏離的樣本,比如年齡為0,或是逾期次數過高進行蓋帽或者是刪除操作,這里采用直接刪除。
#異常值過濾 df1=df1[df1["可用額度比值"]<=1] df1=df1[df1["年齡"]>0] df1=df1[df1["逾期30-59天筆數"]<80] df1=df1[df1["固定資產貸款量"]<50]
三、數據可視化分析
3.1單變量可視化
cut_bins=[0,5000,10000,15000,20000,100000] month_cut=pd.cut(df1["月收入"],cut_bins) month_cut_grouped=df1["好壞客戶"].groupby(month_cut).count() month_cut_grouped1=df1["好壞客戶"].groupby(month_cut).sum() df3=pd.merge(pd.DataFrame(month_cut_grouped), pd.DataFrame(month_cut_grouped1),right_index=True,left_index=True) df3.rename(columns={"好壞客戶_x":"好客戶","好壞客戶_y":"壞客戶"},inplace=True) df3.insert(2,"壞客戶率",df3["壞客戶"]/df3["好客戶"]) plt.figure() ax23=df3[["好客戶","壞客戶"]].plot.bar() ax23.set_xticklabels(df3.index,rotation=15) ax23.set_ylabel("客戶數") ax23.set_title("好壞客戶數與月收入關系") plt.figure() ax231=df3["壞客戶率"].plot() ax231.set_ylabel("壞客戶率") ax231.set_title("月收入與壞客戶率關系")
可以看出客戶主體集中在月收入10000以下的人群,月收入在15000之前的壞客率和月收入呈負相關收入越高壞客率越低,后進入一段平穩但當收入超過20000后,壞客率又在上升。這表明收入在15000以下的人群收入比較穩定,隨着收入越高壞賬率也就越高。而收入大於20000的人群可能從事炒股,創業等風險較大的工作,所以壞賬率增大。
cut_bins=[0,2,4,20] family_cut=pd.cut(df1["家屬數量"],cut_bins) family_cut_grouped=df1["好壞客戶"].groupby(family_cut).count() family_cut_grouped1=df1["好壞客戶"].groupby(family_cut).sum() df4=pd.merge(pd.DataFrame(family_cut_grouped), pd.DataFrame(family_cut_grouped1),right_index=True,left_index=True) df4.rename(columns={"好壞客戶_x":"好客戶","好壞客戶_y":"壞客戶"},inplace=True) df4.insert(2,"壞客戶率",df4["壞客戶"]/df4["好客戶"]) plt.figure() ax24=df4[["好客戶","壞客戶"]].plot.bar() ax24.set_xticklabels(df4.index,rotation=15) ax24.set_ylabel("客戶數") ax24.set_title("好壞客戶數與家屬數量關系") plt.figure() ax241=df4["壞客戶率"].plot() ax241.set_ylabel("壞客戶率") ax241.set_title("壞客戶率與家屬數量的關系")
可以看出客戶的家屬數量的主要集中在0-2之間,家屬數量和壞客率呈線性相關,也就是說隨着家屬數量提升,壞客率也在顯著提升。可能是由於家屬數量大,家庭的支出也就增大,所以更容易出現壞賬的情況。
3.2多變量可視化
通過變量直接的相關性系數,建立相關性矩陣,觀察變量之間的關系,可以進行初步的多重共線性篩選。
plt.rcParams["font.sans-serif"]='SimHei' plt.rcParams['axes.unicode_minus'] = False corr = df1.corr()#計算各變量的相關性系數 xticks = list(corr.index) yticks = list(corr.index) fig = plt.figure(figsize=(10,7)) ax1 = fig.add_subplot(1, 1, 1) sns.heatmap(corr, annot=True, cmap="rainbow",ax=ax1,linewidths=.5, annot_kws={'size': 9, 'weight': 'bold', 'color': 'blue'}) ax1.set_xticklabels(xticks, rotation=35, fontsize=10) ax1.set_yticklabels(yticks, rotation=0, fontsize=10) plt.show()
熱力圖的顏色表示變量之間的相關性程度,可以看出變量之間沒有相關性過高的情況,所以暫時不需要考慮多重共線性的問題。
四、特征工程
4.1 特征分箱
在建立風控評分卡中,一般會對特征進行分箱,以提高模型的穩定性和健壯性,消除了異常波動對評分結果的影響。
#數據分箱 cut1=pd.qcut(df1["可用額度比值"],4,labels=False) cut2=pd.qcut(df1["年齡"],8,labels=False) bins3=[-1,0,1,3,5,13] cut3=pd.cut(df1["逾期30-59天筆數"],bins3,labels=False) cut4=pd.qcut(df1["負債率"],3,labels=False) cut5=pd.qcut(df1["月收入"],4,labels=False) cut6=pd.qcut(df1["信貸數量"],4,labels=False) bins7=[-1, 0, 1, 3,5, 20] cut7=pd.cut(df1["逾期90天筆數"],bins7,labels=False) bins8=[-1, 0,1,2, 3, 33] cut8=pd.cut(df1["固定資產貸款量"],bins8,labels=False) bins9=[-1, 0, 1, 3, 12] cut9=pd.cut(df1["逾期60-89天筆數"],bins9,labels=False) bins10=[-1, 0, 1, 2, 3, 5, 21] cut10=pd.cut(df1["家屬數量"],bins10,labels=False)
4.2 woe轉換
接下來給分箱后的數據計算woe值,woe算是一種編碼形式,但是和普通的編碼它實際代表了響應客戶和未響應客戶之間的差異情況。
公式如下:
#好壞客戶比率 rate=df1["好壞客戶"].sum()/(df1["好壞客戶"].count()-df1["好壞客戶"].sum()) #定義woe計算函數 def get_woe_data(cut): grouped=df1["好壞客戶"].groupby(cut,as_index = True).value_counts() woe=np.log(pd.DataFrame(grouped).unstack().iloc[:,1]/pd.DataFrame(grouped).unstack().iloc[:,0]/rate)#計算每個分組的woe值 return woe cut1_woe=get_woe_data(cut1) cut2_woe=get_woe_data(cut2) cut3_woe=get_woe_data(cut3) cut4_woe=get_woe_data(cut4) cut5_woe=get_woe_data(cut5) cut6_woe=get_woe_data(cut6) cut7_woe=get_woe_data(cut7) cut8_woe=get_woe_data(cut8) cut9_woe=get_woe_data(cut9) cut10_woe=get_woe_data(cut10)
4.3 IV值計算
IV的全稱是Information Value,中文意思是信息價值,或者信息量。它的作用其實和gini和信息熵類似,都是用來衡量變量的預測能力,可以通過IV值來達到特征篩選的目的。
#定義IV值計算函數 def get_IV_data(cut,cut_woe): grouped=df1["好壞客戶"].groupby(cut,as_index = True).value_counts() cut_IV=((pd.DataFrame(grouped).unstack().iloc[:,1]/df1["好壞客戶"].sum()-pd.DataFrame(grouped).unstack().iloc[:,0]/(df1["好壞客戶"].count()-df1["好壞客戶"].sum()))*cut_woe).sum() return cut_IV #計算各分組的IV值 cut1_IV=get_IV_data(cut1,cut1_woe) cut2_IV=get_IV_data(cut2,cut2_woe) cut3_IV=get_IV_data(cut3,cut3_woe) cut4_IV=get_IV_data(cut4,cut4_woe) cut5_IV=get_IV_data(cut5,cut5_woe) cut6_IV=get_IV_data(cut6,cut6_woe) cut7_IV=get_IV_data(cut7,cut7_woe) cut8_IV=get_IV_data(cut8,cut8_woe) cut9_IV=get_IV_data(cut9,cut9_woe) cut10_IV=get_IV_data(cut10,cut10_woe) #各組的IV值可視化 df_IV=pd.DataFrame([cut1_IV,cut2_IV,cut3_IV,cut4_IV,cut5_IV,cut6_IV,cut7_IV,cut8_IV,cut9_IV,cut10_IV],index=df1.columns[2:]) df_IV.plot(kind="bar")
通過特征IV的可視化,可以很直觀的觀察特征之間的差異,我們選擇IV較高的特征代入模型。
#定義一個替換函數 def replace_data(cut,cut_woe): a=[] for i in cut.unique(): a.append(i) a.sort() for m in range(len(a)): cut.replace(a[m],cut_woe.values[m],inplace=True) return cut #進行替換 df_new = pd.DataFrame() df_new['可用額度比值']=replace_data(cut1,cut1_woe) df_new["年齡"]=replace_data(cut2,cut2_woe) df_new["逾期30-59天筆數"]=replace_data(cut3,cut3_woe) df_new["逾期90天筆數"]=replace_data(cut7,cut7_woe) df_new["逾期60-89天筆數"]=replace_data(cut9,cut9_woe)
五、建立模型
建立logistics模型,logistics回歸是廣義線性回歸,它的在建立后和線性回歸一樣會賦值給特征不同的權重,很符合建立評分卡的概念。
from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import roc_curve, auc x=df_new y=df1.iloc[:,1] x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0) #模型訓練 model=LogisticRegression() clf=model.fit(x_train,y_train) print("測試成績:{}".format(clf.score(x_test,y_test))) y_pred=clf.predict(x_test) y_pred1=clf.decision_function(x_test)
模型測試效果看起來不錯,但是准確率並不能反映模型的真實效果,下面利用ROC曲線來評估模型。
#繪制ROC曲線以及計算AUC值 fpr, tpr, threshold = roc_curve(y_test, y_pred1) roc_auc = auc(fpr, tpr) plt.plot(fpr, tpr, color='darkorange', label='ROC curve (area = %0.2f)' % roc_auc) plt.plot([0, 1], [0, 1], color='navy', linestyle='--') plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.0]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('ROC_curve') plt.legend(loc="lower right") plt.show()
模型在ROC曲線上大致表現不錯,AUC也達到了0.84。
六、建立評分卡
根據資料查得評分卡創建公式
coe = clf.coef_ factor = clf.intercept_ import numpy as np factor = 20 / np.log(2) offset = 600 - 20 * np.log(20) / np.log(2) #定義變量分數計算函數 def get_score(coe,woe,factor): scores=[] for w in woe: score=round(coe*w*factor,0) scores.append(score) return scores
將數據集代入到自定義函數,計算評分標准。
#計算每個變量得分 x1 = get_score(coe[0][0], cut1_woe, factor) x2 = get_score(coe[0][1], cut2_woe, factor) x3 = get_score(coe[0][2], cut3_woe, factor) x7 = get_score(coe[0][3], cut7_woe, factor) x9 = get_score(coe[0][4], cut9_woe, factor) #打印輸出每個特征對應的分數 print("可用額度比值對應的分數:{}".format(x1)) print("年齡對應的分數:{}".format(x2)) print("逾期30-59天筆數對應的分數:{}".format(x3)) print("逾期90天筆數對應的分數:{}".format(x7)) print("逾期60-89天筆數對應的分數:{}".format(x9))
將用戶數據代入到評分標准后求和,就可以得到該用戶的總分。得分越高代表其越有可能成為壞賬客戶。
總結
基於AI 的機器學習評分卡系統可通過把舊數據(某個時間點后,例如2年)剔除掉后再進行自動建模、模型評估、並不斷優化特征變量,使得系統更加強大。