1. 程式人生 > 其它 >信用評分系統執行原理中篇-分箱邏輯

信用評分系統執行原理中篇-分箱邏輯

技術標籤:平凡人筆記

前言

本篇承接上篇

信用評分系統執行原理上篇

分箱邏輯比較複雜 設計到很多的演算法

為了確保分析的準確性 我通過pycharm編譯器Debug的方式跑這段程式碼

一步一步的分析程式碼的實現邏輯

編譯器環境的準備

python程式碼準備

編譯器配置

python依賴包安裝

pip3installnumpy
pip3installpandas
pip3installmatplotlib==3.2.0
pip3install--target=./venv/lib/python3.7/site-packagesseaborn
pip3installipython
pip3installxlrd
pip3installsklearn

程式碼邏輯分析

自動分箱


#呼叫自定義分箱
dfx1,ivx1,cutx1,woex1=mono_bin(train.SeriousDlqin2yrs,train.RevolvingUtilizationOfUnsecuredLines,n=10)


#自定義自動分箱函式
defmono_bin(Y,X,n=20):
r=0
#好人個數6936
good=Y.sum()
#壞人個數94957
bad=Y.count()-good
#np.abs(0)=0.9272727272727272m
absR=np.abs(r)
whileabsR<1:#滿足迴圈條件進入迴圈體

#先對訓練集X排序再分組
dfX=X.rank(method="first")
cutPd=pd.qcut(dfX,n)
d1=pd.DataFrame({"X":X,"Y":Y,"Bucket":cutPd})#X.rank(method="first")
d2=d1.groupby("Bucket",as_index=True)
d2Mean=d2.mean()
d2MeanX=d2Mean.X
r,p=stats.spearmanr(d2MeanX,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_values(by='min'))
print(d4)
cut=[]
cut.append(float('-inf'))
foriinrange(1,n+1):
qua=X.quantile(i/(n+1))
cut.append(round(qua,4))
cut.append(float('inf'))
woe=list(d4['woe'].round(3))
returnd4,iv,cut,woe

詳細分析分箱邏輯

引數分析
  • train.SeriousDlqin2yrs 對應函式中的X值
610030
269740
649620
222710
216140
..
1330330
1235090
182460
288500
161720
第一列引數表示一行索引值可以理解成唯一主鍵id
第二列引數表示真實值0表示壞客戶,1表示好客戶
  • train.RevolvingUtilizationOfUnsecuredLines 對應函式中的Y值
RevolvingUtilizationOfUnsecuredLines信用卡和個人信用額度的總餘額,除了房地產和沒有分期付款債務,如汽車貸款除以信用額度
610030.119104
269740.042524
649620.067740
222710.866513
216141.000000
...
1330330.367954
1235090.031879
182460.090163
288501.644518
161720.160312
第一列是行索引值
第二列表示總額度
函式實現邏輯分析
Y.sum()表示好人總計
Y.count()表示所有人
Y.count()-good表示壞人個數


a、迴圈初始條件:r=0,n=10

b、while迴圈條件:np.abs(r)<1

取絕對值

c-1、迴圈過程中使用斯皮爾曼等級相關係數演算法重新計算r值

c-2、每次迴圈:n=n-1

第一次迴圈:r=0

np.abs(0)==0進入迴圈體

這個是對訓練集X進行順序排名重複的值誰出現在前面就先排誰

X.rank(method="first")

這裡簡單介紹下 rank排名函式和qcut\cut函式

理解了這些函式的作用就可以更好的理解分箱演算法對於資料處理的過程

  • rank函式

舉一個簡單的例子

有一個數據源欄位:班級、姓名、成績
目的:找出每個班級中排名第二的學生資訊

需要做的步驟:

1、根據班級分組
2、每個組計算排名
3、篩選出排名為第二的學生

此時對於相同成績的同學如何排名

a順序排名先到先得

李四和王五的成績都為30,但是李四出現在王五的前面,所以李四的排名靠前

當method取值為min,max,average時,都是要參考“順序排名”的)


b密集排名:成績相同排名相同

相同成績的同學排名相同,其他依次加1即可

1,2,2,3,4


c跳躍排名:成績相同排名相同

1,2,2,4,5

成績相同的同學,取在順序排名中最小的那個排名作為該值的排名,李四和王五同學排名分別為2和3,那麼當method為min時,取2和3的最小的那個作為第2名作為成績30的排名

rank函式取值範圍

‘average’,’first’,’min’,‘max’,’dense’

min和max是跳躍排名的一種

關於average,成績相同時,取順序排名中所有名次之和除以該成績的個數,即為該成績的名次;比如上述排名中,30排名為2,3,那麼30的排名=(2+3)/2=2.5,成績為50的同學只有1個,且排名為1,那50的排名就位1/1=1。

​關於max,和min一樣也是跳躍排名的一種,成績相同時取順序排名中排名最大的作為該成績的名次,在順序排名中,30最大的排名為3,那麼當引數為max時,30的排名=3,此時,李四和王五的排名都為第3名了。
  • qcut函式

跟cut()按照變數的值對變數進行分割不同,qcut()是按變數的數量來對變數進行分割,並且儘量保證每個分組裡變數的個數相同

例子:把資料由小到大分成四組,並且讓每組資料的數量相同

#把變數由小到大分成四組,並且讓每組變數的數量相同
d_qcut=d.copy()
d_qcut['qcut_group']=pd.qcut(d_qcut['number'],4)
d_qcut

#檢視每個分組裡變數的個數
d_qcut['qcut_group'].value_counts()

使用qcut()對資料進行分割之後,每個分組裡的資料個數都大致相同,但是跟cut()不同的是,每個分組裡值的範圍並不相同

  • cut() 函式

按照指定的邊界值對變數進行分割

#使用bins引數,指定每個分組的邊界
d_cut_bins=d.copy()
d_cut_bins['cut_group']=pd.cut(d_cut_bins['number'],
bins=[0,10,50,100])
d_cut_bins

繼續信用評分系統 分箱程式碼分析

dfX=X.rank(method="first")
cutPd=pd.qcut(dfX,n)

n=10

對dfX分10組每組的數量大小一致

d1=pd.DataFrame({"X":X,"Y":Y,"Bucket":cutPd})
d2=d1.groupby("Bucket",as_index=True)
d2Mean=d2.mean()
d2MeanX=d2Mean.X

使用斯皮爾曼等級相關係數來評估兩個變數之間的相關性

r,p=stats.spearmanr(d2MeanX,d2Mean.Y)
這個具體什麼原理感興趣的朋友可以自己查閱一下資料
每個指標具體計算過程

min最小值d2.min().X
max最大值d2.max().X
total總人數d2.count().Y
sum好人數d2.sum().Y
rate均值d2.mean().Y
woe=np.log((d3['rate']/(1-d3['rate']))/(good/bad))

(好人均值/壞人均值)/(好人人數/壞人人數)取對數即WOE

goodattribute=d3['sum']/good每組好人數量/總的好人數

badattribute=(d3['total']-d3['sum'])/bad每組壞人人數/壞人總人數

iv=((d3['goodattribute']-d3['badattribute'])*d3['woe']).sum()

d4=(d3.sort_values(by='min'))
通過min列排序


該分箱函式最終得到的結果

ivx1:1.0027047570109968
cutx1:[-inf,0.0313,0.1583,0.5605,inf]
woex1:[-1.37,-1.212,-0.288,1.106]