信用風險計量體系包括主體評級模型和債項評級兩部分。主體評級和債項評級均有一系列評級模型組成,其中主體評級模型可用“四張卡”來表示,分別是A卡、B卡、C卡和F卡;債項評級模型通常按照主體的融資用途,分為企業(yè)融資模型、現(xiàn)金流融資模型和項目融資模型等。 我們主要討論主體評級模型的開發(fā)過程。
一、項目流程
典型的信用評分模型如圖1-1所示。信用風險評級模型的主要開發(fā)流程如下:
(1) 數(shù)據(jù)獲取,包括獲取存量客戶及潛在客戶的數(shù)據(jù)。存量客戶是指已經(jīng)在證券公司開展相關融資類業(yè)務的客戶,包括個人客戶和機構客戶;潛在客戶是指未來擬在證券公司開展相關融資類業(yè)務的客戶,主要包括機構客戶,這也是解決證券業(yè)樣本較少的常用方法,這些潛在機構客戶包括上市公司、公開發(fā)行債券的發(fā)債主體、新三板上市公司、區(qū)域股權交易中心掛牌公司、非標融資機構等。
(2) 數(shù)據(jù)預處理,主要工作包括數(shù)據(jù)清洗、缺失值處理、異常值處理,主要是為了將獲取的原始數(shù)據(jù)轉化為可用作模型開發(fā)的格式化數(shù)據(jù)。
(3) 探索性數(shù)據(jù)分析,該步驟主要是獲取樣本總體的大概情況,描述樣本總體情況的指標主要有直方圖、箱形圖等。
(4) 變量選擇,該步驟主要是通過統(tǒng)計學的方法,篩選出對違約狀態(tài)影響最顯著的指標。主要有單變量特征選擇方法和基于機器學習模型的方法 。
(5) 模型開發(fā),該步驟主要包括變量分段、變量的WOE(證據(jù)權重)變換和邏輯回歸估算三部分。
(6) 模型評估,該步驟主要是評估模型的區(qū)分能力、預測能力、穩(wěn)定性,并形成模型評估報告,得出模型是否可以使用的結論。
(7) 信用評分,根據(jù)邏輯回歸的系數(shù)和WOE等確定信用評分的方法。將Logistic模型轉換為標準評分的形式。
(8) 建立評分系統(tǒng),根據(jù)信用評分方法,建立自動信用評分系統(tǒng)。

PS:有些時候為了便于命名,相應的變量用標號代替
二、數(shù)據(jù)獲取
數(shù)據(jù)來自Kaggle的Give Me Some Credit,有15萬條的樣本數(shù)據(jù),下圖可以看到這份數(shù)據(jù)的大致情況。
數(shù)據(jù)屬于個人消費類貸款,只考慮信用評分最終實施時能夠使用到的數(shù)據(jù)應從如下一些方面獲取數(shù)據(jù):
– 基本屬性:包括了借款人當時的年齡。
– 償債能力:包括了借款人的月收入、負債比率。
– 信用往來:兩年內(nèi)35-59天逾期次數(shù)、兩年內(nèi)60-89天逾期次數(shù)、兩年內(nèi)90
天或高于90天逾期的次數(shù)。
– 財產(chǎn)狀況:包括了開放式信貸和貸款數(shù)量、不動產(chǎn)貸款或額度數(shù)量。
– 貸款屬性:暫無。
– 其他因素:包括了借款人的家屬數(shù)量(不包括本人在內(nèi))。
– 時間窗口:自變量的觀察窗口為過去兩年,因變量表現(xiàn)窗口為未來兩年。

三、數(shù)據(jù)預處理
在對數(shù)據(jù)處理之前,需要對數(shù)據(jù)的缺失值和異常值情況進行了解。Python內(nèi)有describe()函數(shù),可以了解數(shù)據(jù)集的缺失值、均值和中位數(shù)等。
#載入數(shù)據(jù)
data = pd.read_csv('cs-training.csv')
#數(shù)據(jù)集確實和分布情況
data.describe().to_csv('DataDescribe.csv')
數(shù)據(jù)集的詳細情況:

從上圖可知,變量MonthlyIncome和NumberOfDependents存在缺失,變量MonthlyIncome共有缺失值29731個,NumberOfDependents有3924個缺失值。
3.1 缺失值處理
這種情況在現(xiàn)實問題中非常普遍,這會導致一些不能處理缺失值的分析方法無法應用,因此,在信用風險評級模型開發(fā)的第一步我們就要進行缺失值處理。缺失值處理的方法,包括如下幾種。
(1) 直接刪除含有缺失值的樣本。
(2) 根據(jù)樣本之間的相似性填補缺失值。
(3) 根據(jù)變量之間的相關關系填補缺失值。
變量MonthlyIncome缺失率比較大,所以我們根據(jù)變量之間的相關關系填補缺失值,我們采用隨機森林法:
# 用隨機森林對缺失值預測填充函數(shù)
def set_missing(df):
# 把已有的數(shù)值型特征取出來
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)
# 用得到的預測結果填補原缺失數(shù)據(jù)
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)
3.2 異常值處理
缺失值處理完畢后,我們還需要進行異常值處理。異常值是指明顯偏離大多數(shù)抽樣數(shù)據(jù)的數(shù)值,比如個人客戶的年齡為0時,通常認為該值為異常值。找出樣本總體中的異常值,通常采用離群值檢測的方法。
首先,我們發(fā)現(xiàn)變量age中存在0,顯然是異常值,直接剔除:
# 年齡等于0的異常值進行剔除
data = data[data['age'] > 0]
對于變量NumberOfTime30-59DaysPastDueNotWorse、NumberOfTimes90DaysLate、NumberOfTime60-89DaysPastDueNotWorse這三個變量,由下面的箱線圖圖3-2可以看出,均存在異常值,且由unique函數(shù)可以得知均存在96、98兩個異常值,因此予以剔除。同時會發(fā)現(xiàn)剔除其中一個變量的96、98值,其他變量的96、98兩個值也會相應被剔除。

剔除變量NumberOfTime30-59DaysPastDueNotWorse、NumberOfTimes90DaysLate、NumberOfTime60-89DaysPastDueNotWorse的異常值。另外,數(shù)據(jù)集中好客戶為0,違約客戶為1,考慮到正常的理解,能正常履約并支付利息的客戶為1,所以我們將其取反。
#剔除異常值
data = data[data['NumberOfTime30-59DaysPastDueNotWorse'] < 90]
#變量SeriousDlqin2yrs取反
data['SeriousDlqin2yrs']=1-data['SeriousDlqin2yrs']
3.3 數(shù)據(jù)切分
為了驗證模型的擬合效果,我們需要對數(shù)據(jù)集進行切分,分成訓練集和測試集。
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)
四、探索性分析
在建立模型之前,我們一般會對現(xiàn)有的數(shù)據(jù)進行 探索性數(shù)據(jù)分析(Exploratory Data Analysis) 。 EDA是指對已有的數(shù)據(jù)(特別是調(diào)查或觀察得來的原始數(shù)據(jù))在盡量少的先驗假定下進行探索。常用的探索性數(shù)據(jù)分析方法有:直方圖、散點圖和箱線圖等。
客戶年齡分布如圖4-1所示,可以看到年齡變量大致呈正態(tài)分布,符合統(tǒng)計分析的假設。

客戶年收入分布如圖4-2所示,月收入也大致呈正態(tài)分布,符合統(tǒng)計分析的需要。

五、變量選擇
特征變量選擇(排序)對于數(shù)據(jù)分析、機器學習從業(yè)者來說非常重要。好的特征選擇能夠提升模型的性能,更能幫助我們理解數(shù)據(jù)的特點、底層結構,這對進一步改善模型、算法都有著重要作用。至于Python的變量選擇代碼實現(xiàn)可以參考結合Scikit-learn介紹幾種常用的特征選擇方法。
在本文中,我們采用信用評分模型的變量選擇方法,通過WOE分析方法,即是通過比較指標分箱和對應分箱的違約概率來確定指標是否符合經(jīng)濟意義。首先我們對變量進行離散化(分箱)處理。
5.1 分箱處理
變量分箱(binning)是對連續(xù)變量離散化(discretization)的一種稱呼。信用評分卡開發(fā)中一般有常用的等距分段、等深分段、最優(yōu)分段。其中等距分段(Equval length intervals)是指分段的區(qū)間是一致的,比如年齡以十年作為一個分段;等深分段(Equal frequency intervals)是先確定分段數(shù)量,然后令每個分段中數(shù)據(jù)數(shù)量大致相等;最優(yōu)分段(Optimal Binning)又叫監(jiān)督離散化(supervised discretizaion),使用遞歸劃分(Recursive Partitioning)將連續(xù)變量分為分段,背后是一種基于條件推斷查找較佳分組的算法。
我們首先選擇對連續(xù)變量進行最優(yōu)分段,在連續(xù)變量的分布不滿足最優(yōu)分段的要求時,再考慮對連續(xù)變量進行等距分段。最優(yōu)分箱的代碼如下:
# 定義自動分箱函數(shù)
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
針對我們將使用最優(yōu)分段對于數(shù)據(jù)集中的RevolvingUtilizationOfUnsecuredLines、age、DebtRatio和MonthlyIncome進行分類。




針對不能最優(yōu)分箱的變量,分箱如下:
# 連續(xù)變量離散化
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]
5.2 WOE
WoE分析, 是對指標分箱、計算各個檔位的WoE值并觀察WoE值隨指標變化的趨勢。其中WoE的數(shù)學定義是:
woe=ln(goodattribute/badattribute)
在進行分析時,我們需要對各指標從小到大排列,并計算出相應分檔的WoE值。其中正向指標越大,WoE值越??;反向指標越大,WoE值越大。正向指標的WoE值負斜率越大,反響指標的正斜率越大,則說明指標區(qū)分能力好。WoE值趨近于直線,則意味指標判斷能力較弱。若正向指標和WoE正相關趨勢、反向指標同WoE出現(xiàn)負相關趨勢,則說明此指標不符合經(jīng)濟意義,則應當予以去除。
woe函數(shù)實現(xiàn)在上一節(jié)的mono_bin()函數(shù)里面已經(jīng)包含,這里不再重復。
5.3 相關性分析和IV篩選
接下來,我們會用經(jīng)過清洗后的數(shù)據(jù)看一下變量間的相關性。注意,這里的相關性分析只是初步的檢查,進一步檢查模型的VI(證據(jù)權重)作為變量篩選的依據(jù)。
相關性圖我們通過Python里面的seaborn包,調(diào)用heatmap()繪圖函數(shù)進行繪制,實現(xiàn)代碼如下:
corr = data.corr()#計算各變量的相關性系數(shù)
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'})#繪制相關性系數(shù)熱力圖
ax1.set_xticklabels(xticks, rotation=0, fontsize=10)
ax1.set_yticklabels(yticks, rotation=0, fontsize=10)
plt.show()
生成的圖形如圖5-5所示:

由上圖可以看出,各變量之間的相關性是非常小的。NumberOfOpenCreditLinesAndLoans和NumberRealEstateLoansOrLines的相關性系數(shù)為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的實現(xiàn)放在mono_bin()函數(shù)里面,代碼實現(xiàn)如下:
# 定義自動分箱函數(shù)
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)
#在柱狀圖上添加數(shù)字標簽
for a, b in zip(x, ivlist):
plt.text(a, b + 0.01, '%.4f' % b, ha='center', va='bottom', fontsize=10)
plt.show()
輸出圖像:

可以看出,DebtRatio、MonthlyIncome、NumberOfOpenCreditLinesAndLoans、NumberRealEstateLoansOrLines和NumberOfDependents變量的IV值明顯較低,所以予以刪除。
小結
本文主要介紹了信用評分模型開發(fā)過程中的數(shù)據(jù)預處理、探索性分析和變量選擇。數(shù)據(jù)預處理主要針對缺失值用隨機森林法和直接剔除法進行處理,對于異常值主要根據(jù)實際情況和箱形圖的數(shù)據(jù)分布,對異常值進行剔除;探索性分析主要對各變量的分布情況進行初始的探究;變量選擇主要考慮了變量的分箱方法,根據(jù)分箱結果計算WOE值,然后檢查變量之間的相關性,根據(jù)各變量的IV值來選擇對數(shù)據(jù)處理有好效果的變量。
接下來會介紹信用評分模型的模型開發(fā)、模型評估和信用評分等。
基于Python的信用評分卡模型分析(二)