信用風險計量體系包括主體評級模型和債項評級兩部分。主體評級和債項評級均有一系列評級模型組成,其中主體評級模型可用「四張卡」來表示,分別是A卡、B卡、C卡和F卡;債項評級模型一般按照主體的融資用途,分爲企業融資模型、現金流融資模型和項目融資模型等。 咱們主要討論主體評級模型的開發過程。html
典型的信用評分模型如圖1-1所示。信用風險評級模型的主要開發流程以下:
(1) 數據獲取,包括獲取存量客戶及潛在客戶的數據。存量客戶是指已經在證券公司開展相關融資類業務的客戶,包括我的客戶和機構客戶;潛在客戶是指將來擬在證券公司開展相關融資類業務的客戶,主要包括機構客戶,這也是解決證券業樣本較少的經常使用方法,這些潛在機構客戶包括上市公司、公開發行債券的發債主體、新三板上市公司、區域股權交易中心掛牌公司、非標融資機構等。
(2) 數據預處理,主要工做包括數據清洗、缺失值處理、異常值處理,主要是爲了將獲取的原始數據轉化爲可用做模型開發的格式化數據。
(3) 探索性數據分析,該步驟主要是獲取樣本整體的大概狀況,描述樣本整體狀況的指標主要有直方圖、箱形圖等。
(4) 變量選擇,該步驟主要是經過統計學的方法,篩選出對違約狀態影響最顯著的指標。主要有單變量特徵選擇方法和基於機器學習模型的方法 。
(5) 模型開發,該步驟主要包括變量分段、變量的WOE(證據權重)變換和邏輯迴歸估算三部分。
(6) 模型評估,該步驟主要是評估模型的區分能力、預測能力、穩定性,並造成模型評估報告,得出模型是否可使用的結論。
(7) 信用評分,根據邏輯迴歸的係數和WOE等肯定信用評分的方法。將Logistic模型轉換爲標準評分的形式。
(8) 創建評分系統,根據信用評分方法,創建自動信用評分系統。python
圖1-1 信用評分模型開發流程git
PS:有些時候爲了便於命名,相應的變量用標號代替算法
數據來自Kaggle的Give Me Some Credit,有15萬條的樣本數據,下圖能夠看到這份數據的大體狀況。
數據屬於我的消費類貸款,只考慮信用評分最終實施時可以使用到的數據應從以下一些方面獲取數據:
– 基本屬性:包括了借款人當時的年齡。
– 償債能力:包括了借款人的月收入、負債比率。
– 信用往來:兩年內35-59天逾期次數、兩年內60-89天逾期次數、兩年內90
天或高於90天逾期的次數。
– 財產情況:包括了開放式信貸和貸款數量、不動產貸款或額度數量。
– 貸款屬性:暫無。
– 其餘因素:包括了借款人的家眷數量(不包括本人在內)。
– 時間窗口:自變量的觀察窗口爲過去兩年,因變量表現窗口爲將來兩年。app
圖2-1 原始數據的變量dom
在對數據處理以前,須要對數據的缺失值和異常值狀況進行了解。Python內有describe()函數,能夠了解數據集的缺失值、均值和中位數等。機器學習
#載入數據 data = pd.read_csv('cs-training.csv') #數據集確實和分佈狀況 data.describe().to_csv('DataDescribe.csv')
數據集的詳細狀況:ide
圖3-1 變量詳細狀況wordpress
從上圖可知,變量MonthlyIncome和NumberOfDependents存在缺失,變量MonthlyIncome共有缺失值29731個,NumberOfDependents有3924個缺失值。函數
這種狀況在現實問題中很是廣泛,這會致使一些不能處理缺失值的分析方法沒法應用,所以,在信用風險評級模型開發的第一步咱們就要進行缺失值處理。缺失值處理的方法,包括以下幾種。
(1) 直接刪除含有缺失值的樣本。
(2) 根據樣本之間的類似性填補缺失值。
(3) 根據變量之間的相關關係填補缺失值。
變量MonthlyIncome缺失率比較大,因此咱們根據變量之間的相關關係填補缺失值,咱們採用隨機森林法:
# 用隨機森林對缺失值預測填充函數 def set_missing(df): # 把已有的數值型特徵取出來 process_df = df.ix[:,[5,0,1,2,3,4,6,7,8,9]] # 分紅已知該特徵和未知該特徵兩部分 known = process_df[process_df.MonthlyIncome.notnull()].as_matrix() unknown = process_df[process_df.MonthlyIncome.isnull()].as_matrix() # X爲特徵屬性值 X = known[:, 1:] # y爲結果標籤值 y = known[:, 0] # fit到RandomForestRegressor之中 rfr = RandomForestRegressor(random_state=0, n_estimators=200,max_depth=3,n_jobs=-1) rfr.fit(X,y) # 用獲得的模型進行未知特徵值預測 predicted = rfr.predict(unknown[:, 1:]).round(0) print(predicted) # 用獲得的預測結果填補原缺失數據 df.loc[(df.MonthlyIncome.isnull()), 'MonthlyIncome'] = predicted return df
NumberOfDependents變量缺失值比較少,直接刪除,對整體模型不會形成太大影響。對缺失值處理完以後,刪除重複項。
data=set_missing(data)#用隨機森林填補比較多的缺失值 data=data.dropna()#刪除比較少的缺失值 data = data.drop_duplicates()#刪除重複項 data.to_csv('MissingData.csv',index=False)
缺失值處理完畢後,咱們還須要進行異常值處理。異常值是指明顯偏離大多數抽樣數據的數值,好比我的客戶的年齡爲0時,一般認爲該值爲異常值。找出樣本整體中的異常值,一般採用離羣值檢測的方法。
首先,咱們發現變量age中存在0,顯然是異常值,直接剔除:
# 年齡等於0的異常值進行剔除 data = data[data['age'] > 0]
對於變量NumberOfTime30-59DaysPastDueNotWorse、NumberOfTimes90DaysLate、NumberOfTime60-89DaysPastDueNotWorse這三個變量,由下面的箱線圖圖3-2能夠看出,均存在異常值,且由unique函數能夠得知均存在9六、98兩個異常值,所以予以剔除。同時會發現剔除其中一個變量的9六、98值,其餘變量的9六、98兩個值也會相應被剔除。
圖3-2 箱形圖
剔除變量NumberOfTime30-59DaysPastDueNotWorse、NumberOfTimes90DaysLate、NumberOfTime60-89DaysPastDueNotWorse的異常值。另外,數據集中好客戶爲0,違約客戶爲1,考慮到正常的理解,能正常履約並支付利息的客戶爲1,因此咱們將其取反。
#剔除異常值 data = data[data['NumberOfTime30-59DaysPastDueNotWorse'] < 90] #變量SeriousDlqin2yrs取反 data['SeriousDlqin2yrs']=1-data['SeriousDlqin2yrs']
爲了驗證模型的擬合效果,咱們須要對數據集進行切分,分紅訓練集和測試集。
from sklearn.cross_validation import train_test_split
Y = data['SeriousDlqin2yrs'] X = data.ix[:, 1:] #測試集佔比30% X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=0) # print(Y_train) train = pd.concat([Y_train, X_train], axis=1) test = pd.concat([Y_test, X_test], axis=1) clasTest = test.groupby('SeriousDlqin2yrs')['SeriousDlqin2yrs'].count() train.to_csv('TrainData.csv',index=False) test.to_csv('TestData.csv',index=False)
在創建模型以前,咱們通常會對現有的數據進行 探索性數據分析(Exploratory Data Analysis) 。 EDA是指對已有的數據(特別是調查或觀察得來的原始數據)在儘可能少的先驗假定下進行探索。經常使用的探索性數據分析方法有:直方圖、散點圖和箱線圖等。
客戶年齡分佈如圖4-1所示,能夠看到年齡變量大體呈正態分佈,符合統計分析的假設。
圖4-1 客戶年齡分佈
客戶年收入分佈如圖4-2所示,月收入也大體呈正態分佈,符合統計分析的須要。
圖4-2 客戶收入分佈
特徵變量選擇(排序)對於數據分析、機器學習從業者來講很是重要。好的特徵選擇可以提高模型的性能,更能幫助咱們理解數據的特色、底層結構,這對進一步改善模型、算法都有着重要做用。至於Python的變量選擇代碼實現能夠參考結合Scikit-learn介紹幾種經常使用的特徵選擇方法。
在本文中,咱們採用信用評分模型的變量選擇方法,經過WOE分析方法,便是經過比較指標分箱和對應分箱的違約機率來肯定指標是否符合經濟意義。首先咱們對變量進行離散化(分箱)處理。
變量分箱(binning)是對連續變量離散化(discretization)的一種稱呼。信用評分卡開發中通常有經常使用的等距分段、等深分段、最優分段。其中等距分段(Equval length intervals)是指分段的區間是一致的,好比年齡以十年做爲一個分段;等深分段(Equal frequency intervals)是先肯定分段數量,而後令每一個分段中數據數量大體相等;最優分段(Optimal Binning)又叫監督離散化(supervised discretizaion),使用遞歸劃分(Recursive Partitioning)將連續變量分爲分段,背後是一種基於條件推斷查找較佳分組的算法。
咱們首先選擇對連續變量進行最優分段,在連續變量的分佈不知足最優分段的要求時,再考慮對連續變量進行等距分段。最優分箱的代碼以下:
# 定義自動分箱函數 def mono_bin(Y, X, n = 20): r = 0 good=Y.sum() bad=Y.count()-good while np.abs(r) < 1: d1 = pd.DataFrame({"X": X, "Y": Y, "Bucket": pd.qcut(X, n)}) d2 = d1.groupby('Bucket', as_index = True) r, p = stats.spearmanr(d2.mean().X, d2.mean().Y) n = n - 1 d3 = pd.DataFrame(d2.X.min(), columns = ['min']) d3['min']=d2.min().X d3['max'] = d2.max().X d3['sum'] = d2.sum().Y d3['total'] = d2.count().Y d3['rate'] = d2.mean().Y d3['woe']=np.log((d3['rate']/(1-d3['rate']))/(good/bad)) d4 = (d3.sort_index(by = 'min')).reset_index(drop=True) print("=" * 60) print(d4) return d4
針對咱們將使用最優分段對於數據集中的RevolvingUtilizationOfUnsecuredLines、age、DebtRatio和MonthlyIncome進行分類。
圖5-1 RevolvingUtilizationOfUnsecuredLines分箱狀況.png
圖5-2 age分箱狀況.png
圖5-3 DebtRatio分箱狀況.png
圖5-4 MonthlyIncome分箱狀況.png
針對不能最優分箱的變量,分箱以下:
# 連續變量離散化 cutx3 = [ninf, 0, 1, 3, 5, pinf] cutx6 = [ninf, 1, 2, 3, 5, pinf] cutx7 = [ninf, 0, 1, 3, 5, pinf] cutx8 = [ninf, 0,1,2, 3, pinf] cutx9 = [ninf, 0, 1, 3, pinf] cutx10 = [ninf, 0, 1, 2, 3, 5, pinf]
WoE分析, 是對指標分箱、計算各個檔位的WoE值並觀察WoE值隨指標變化的趨勢。其中WoE的數學定義是:
woe=ln(goodattribute/badattribute)
在進行分析時,咱們須要對各指標從小到大排列,並計算出相應分檔的WoE值。其中正向指標越大,WoE值越小;反向指標越大,WoE值越大。正向指標的WoE值負斜率越大,反響指標的正斜率越大,則說明指標區分能力好。WoE值趨近於直線,則意味指標判斷能力較弱。若正向指標和WoE正相關趨勢、反向指標同WoE出現負相關趨勢,則說明此指標不符合經濟意義,則應當予以去除。
woe函數實如今上一節的mono_bin()函數裏面已經包含,這裏再也不重複。
接下來,咱們會用通過清洗後的數據看一下變量間的相關性。注意,這裏的相關性分析只是初步的檢查,進一步檢查模型的VI(證據權重)做爲變量篩選的依據。
相關性圖咱們經過Python裏面的seaborn包,調用heatmap()繪圖函數進行繪製,實現代碼以下:
corr = data.corr()#計算各變量的相關性係數 xticks = ['x0','x1','x2','x3','x4','x5','x6','x7','x8','x9','x10']#x軸標籤 yticks = list(corr.index)#y軸標籤 fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) sns.heatmap(corr, annot=True, cmap='rainbow', ax=ax1, annot_kws={'size': 9, 'weight': 'bold', 'color': 'blue'})#繪製相關性係數熱力圖 ax1.set_xticklabels(xticks, rotation=0, fontsize=10) ax1.set_yticklabels(yticks, rotation=0, fontsize=10) plt.show()
生成的圖形如圖5-5所示:
圖5-5 數據集各變量的相關性
由上圖能夠看出,各變量之間的相關性是很是小的。NumberOfOpenCreditLinesAndLoans和NumberRealEstateLoansOrLines的相關性係數爲0.43。
接下來,我進一步計算每一個變量的Infomation Value(IV)。IV指標是通常用來肯定自變量的預測能力。 其公式爲:
IV=sum((goodattribute-badattribute)*ln(goodattribute/badattribute))
經過IV值判斷變量預測能力的標準是:
< 0.02: unpredictive
0.02 to 0.1: weak
0.1 to 0.3: medium
0.3 to 0.5: strong
> 0.5: suspicious
IV的實現放在mono_bin()函數裏面,代碼實現以下:
# 定義自動分箱函數 def mono_bin(Y, X, n = 20): r = 0 good=Y.sum() bad=Y.count()-good while np.abs(r) < 1: d1 = pd.DataFrame({"X": X, "Y": Y, "Bucket": pd.qcut(X, n)}) d2 = d1.groupby('Bucket', as_index = True) r, p = stats.spearmanr(d2.mean().X, d2.mean().Y) n = n - 1 d3 = pd.DataFrame(d2.X.min(), columns = ['min']) d3['min']=d2.min().X d3['max'] = d2.max().X d3['sum'] = d2.sum().Y d3['total'] = d2.count().Y d3['rate'] = d2.mean().Y d3['woe']=np.log((d3['rate']/(1-d3['rate']))/(good/bad)) d3['goodattribute']=d3['sum']/good d3['badattribute']=(d3['total']-d3['sum'])/bad iv=((d3['goodattribute']-d3['badattribute'])*d3['woe']).sum() d4 = (d3.sort_index(by = 'min')).reset_index(drop=True) print("=" * 60) print(d4) cut=[] cut.append(float('-inf')) for i in range(1,n+1): qua=X.quantile(i/(n+1)) cut.append(round(qua,4)) cut.append(float('inf')) woe=list(d4['woe'].round(3)) return d4,iv,cut,woe
生成的IV圖代碼:
ivlist=[ivx1,ivx2,ivx3,ivx4,ivx5,ivx6,ivx7,ivx8,ivx9,ivx10]#各變量IV index=['x1','x2','x3','x4','x5','x6','x7','x8','x9','x10']#x軸的標籤 fig1 = plt.figure(1) ax1 = fig1.add_subplot(1, 1, 1) x = np.arange(len(index))+1 ax1.bar(x, ivlist, width=0.4)#生成柱狀圖 ax1.set_xticks(x) ax1.set_xticklabels(index, rotation=0, fontsize=12) ax1.set_ylabel('IV(Information Value)', fontsize=14) #在柱狀圖上添加數字標籤 for a, b in zip(x, ivlist): plt.text(a, b + 0.01, '%.4f' % b, ha='center', va='bottom', fontsize=10) plt.show()
輸出圖像:
圖5-6 輸出的各變量IV圖
能夠看出,DebtRatio、MonthlyIncome、NumberOfOpenCreditLinesAndLoans、NumberRealEstateLoansOrLines和NumberOfDependents變量的IV值明顯較低,因此予以刪除。
本文主要介紹了信用評分模型開發過程當中的數據預處理、探索性分析和變量選擇。數據預處理主要針對缺失值用隨機森林法和直接剔除法進行處理,對於異常值主要根據實際狀況和箱形圖的數據分佈,對異常值進行剔除;探索性分析主要對各變量的分佈狀況進行初始的探究;變量選擇主要考慮了變量的分箱方法,根據分箱結果計算WOE值,而後檢查變量之間的相關性,根據各變量的IV值來選擇對數據處理有好效果的變量。
接下來會介紹信用評分模型的模型開發、模型評估和信用評分等。
上一篇文章基於Python的信用評分卡模型分析(一)已經介紹了信用評分卡模型的數據預處理、探索性數據分析、變量分箱和變量選擇等。接下來咱們將繼續討論信用評分卡的模型實現和分析,信用評分的方法和自動評分系統。
證據權重(Weight of Evidence,WOE)轉換能夠將Logistic迴歸模型轉變爲標準評分卡格式。引入WOE轉換的目的並非爲了提升模型質量,只是一些變量不該該被歸入模型,這或者是由於它們不能增長模型值,或者是由於與其模型相關係數有關的偏差較大,其實創建標準信用評分卡也能夠不採用WOE轉換。這種狀況下,Logistic迴歸模型須要處理更大數量的自變量。儘管這樣會增長建模程序的複雜性,但最終獲得的評分卡都是同樣的。
在創建模型以前,咱們須要將篩選後的變量轉換爲WoE值,便於信用評分。
咱們已經能獲取了每一個變量的分箱數據和woe數據,只須要根據各變量數據進行替換,實現代碼以下:
#替換成woe函數 def replace_woe(series,cut,woe): list=[] i=0 while i<len(series): value=series[i] j=len(cut)-2 m=len(cut)-2 while j>=0: if value>=cut[j]: j=-1 else: j -=1 m -= 1 list.append(woe[m]) i += 1 return list
咱們將每一個變量都進行替換,並將其保存到WoeData.csv文件中:
# 替換成woe data['RevolvingUtilizationOfUnsecuredLines'] = Series(replace_woe(data['RevolvingUtilizationOfUnsecuredLines'], cutx1, woex1)) data['age'] = Series(replace_woe(data['age'], cutx2, woex2)) data['NumberOfTime30-59DaysPastDueNotWorse'] = Series(replace_woe(data['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, woex3)) data['DebtRatio'] = Series(replace_woe(data['DebtRatio'], cutx4, woex4)) data['MonthlyIncome'] = Series(replace_woe(data['MonthlyIncome'], cutx5, woex5)) data['NumberOfOpenCreditLinesAndLoans'] = Series(replace_woe(data['NumberOfOpenCreditLinesAndLoans'], cutx6, woex6)) data['NumberOfTimes90DaysLate'] = Series(replace_woe(data['NumberOfTimes90DaysLate'], cutx7, woex7)) data['NumberRealEstateLoansOrLines'] = Series(replace_woe(data['NumberRealEstateLoansOrLines'], cutx8, woex8)) data['NumberOfTime60-89DaysPastDueNotWorse'] = Series(replace_woe(data['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, woex9)) data['NumberOfDependents'] = Series(replace_woe(data['NumberOfDependents'], cutx10, woex10)) data.to_csv('WoeData.csv', index=False)
咱們直接調用statsmodels包來實現邏輯迴歸:
導入數據 data = pd.read_csv('WoeData.csv') #應變量 Y=data['SeriousDlqin2yrs'] #自變量,剔除對因變量影響不明顯的變量 X=data.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1) X1=sm.add_constant(X) logit=sm.Logit(Y,X1) result=logit.fit() print(result.summary())
輸出結果:
圖6-1 邏輯迴歸模型結果.png
經過圖6-1可知,邏輯迴歸各變量都已經過顯著性檢驗,知足要求。
到這裏,咱們的建模部分基本結束了。咱們須要驗證一下模型的預測能力如何。咱們使用在建模開始階段預留的test數據進行檢驗。經過ROC曲線和AUC來評估模型的擬合能力。
在Python中,能夠利用sklearn.metrics,它能方便比較兩個分類器,自動計算ROC和AUC。
實現代碼:
#應變量 Y_test = test['SeriousDlqin2yrs'] #自變量,剔除對因變量影響不明顯的變量,與模型變量對應 X_test = test.drop(['SeriousDlqin2yrs', 'DebtRatio', 'MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines', 'NumberOfDependents'], axis=1) X3 = sm.add_constant(X_test) resu = result.predict(X3)#進行預測 fpr, tpr, threshold = roc_curve(Y_test, resu) rocauc = auc(fpr, tpr)#計算AUC plt.plot(fpr, tpr, 'b', label='AUC = %0.2f' % rocauc)#生成ROC曲線 plt.legend(loc='lower right') plt.plot([0, 1], [0, 1], 'r--') plt.xlim([0, 1]) plt.ylim([0, 1]) plt.ylabel('真正率') plt.xlabel('假正率') plt.show()
輸出結果:
圖6-2 ROC曲線
從上圖可知,AUC值爲0.85,說明該模型的預測效果仍是不錯的,正確率較高。
咱們已經基本完成了建模相關的工做,並用ROC曲線驗證了模型的預測能力。接下來的步驟,就是將Logistic模型轉換爲標準評分卡的形式。
依據以上論文資料獲得:
a=log(p_good/P_bad)
Score = offset + factor * log(odds)
在創建標準評分卡以前,咱們須要選取幾個評分卡參數:基礎分值、 PDO(比率翻倍的分值)和好壞比。 這裏, 咱們取600分爲基礎分值,PDO爲20 (每高20分好壞比翻一倍),好壞比取20。
# 咱們取600分爲基礎分值,PDO爲20(每高20分好壞比翻一倍),好壞比取20。 p = 20 / math.log(2) q = 600 - 20 * math.log(20) / math.log(2) baseScore = round(q + p * coe[0], 0)
我的總評分=基礎分+各部分得分
下面計算各變量部分的分數。各部分得分函數:
#計算分數函數 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[1], woex1, p) x2 = get_score(coe[2], woex2, p) x3 = get_score(coe[3], woex3, p) x7 = get_score(coe[4], woex7, p) x9 = get_score(coe[5], woex9, p)
咱們能夠獲得各部分的評分卡如圖7-1所示:
圖7-1 各變量的評分標準
根據變量來計算分數,實現以下:
#根據變量計算分數 def compute_score(series,cut,score): list = [] i = 0 while i < len(series): value = series[i] j = len(cut) - 2 m = len(cut) - 2 while j >= 0: if value >= cut[j]: j = -1 else: j -= 1 m -= 1 list.append(score[m]) i += 1 return list
咱們來計算test裏面的分數:
test1 = pd.read_csv('TestData.csv') test1['BaseScore']=Series(np.zeros(len(test1)))+baseScore test1['x1'] = Series(compute_score(test1['RevolvingUtilizationOfUnsecuredLines'], cutx1, x1)) test1['x2'] = Series(compute_score(test1['age'], cutx2, x2)) test1['x3'] = Series(compute_score(test1['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, x3)) test1['x7'] = Series(compute_score(test1['NumberOfTimes90DaysLate'], cutx7, x7)) test1['x9'] = Series(compute_score(test1['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, x9)) test1['Score'] = test1['x1'] + test1['x2'] + test1['x3'] + test1['x7'] +test1['x9'] + baseScore test1.to_csv('ScoreData.csv', index=False)
批量計算的部分分結果:
圖8-1 批量計算的部分結果
本文經過對kaggle上的Give Me Some Credit數據的挖掘分析,結合信用評分卡的創建原理,從數據的預處理、變量選擇、建模分析到建立信用評分,建立了一個簡單的信用評分系統。
基於AI 的機器學習評分卡系統可經過把舊數據(某個時間點後,例如2年)剔除掉後再進行自動建模、模型評估、並不斷優化特徵變量,使得系統更增強大。
基於R語言的信用評分卡建模分析
信用卡評分模型
信用標準評分卡模型開發及實現
手把手教你用R語言創建信用評分模型
Scorecard 評分卡模型
使用python進行數據清洗
Monotonic Binning with Python
Python異常值處理與檢測
結合Scikit-learn介紹幾種經常使用的特徵選擇方法
連接:http://pan.baidu.com/s/1gfEj4n5 密碼:55qt