• 用戶屬性有千千萬萬個維度,而評分卡模型所選用的欄位在30個以下,那麼怎樣挑選這些欄位呢?
  • 評分卡模型採用的是對每個欄位的分段進行評分,那麼怎樣對評分卡進行有效的分段呢?
  • 最關鍵的,怎麼對每個欄位的每個分段進行評分呢?這個評分是怎麼來的?

評分卡構建流程

  • 變數選擇

選擇上基本幾個方面:客戶的物理屬性;貸前、貸中、貸後的表現,比如逾期、餘額等;實際應用中,很多根據業務背景,構造特徵變數(或者稱為衍生變數),形如:(aX+bY)/z。

因變數:一般逾期90天以上的客戶標記為0(壞客戶),其他為1(好客戶)。

  • 變數篩選

單變數:歸一化,離散化,缺失值處理

多變數:降維,相關係數,卡方檢驗,信息增益,決策樹等。

行業經常使用基於IV值進行篩選的方式。

  • IV(Information Value)

IV的全稱是Information Value,中文意思是信息價值,或者信息量。求IV值得先求WOE,這裡又引入WOE的概念。

  • WOE(Weight of Evidence)證據權重

對於WOE,首先把變數分組(怎麼分後面說),然後對於每個組i,對於第i組有:

woe反映的是:在自變數每個分組下違約用戶對正常用戶佔比和總體中違約用戶對正常用戶佔比之間的差異;從而可以直觀的認為woe蘊含了自變數取值對於目標變數(違約概率)的影響。

  • IV計算

IV稱為信息價值(information value),是一般用來確定自變數的預測能力,對變數進行篩選,自變數的IV值越大,表示自變數的預測能力越強。其公式為:

我們可以看到IV值其實是WOE值加權求和,這個加權主要是消除掉各分組中數量差異帶來的誤差。

比如如果只用woe的絕對值求和,如果一些分組中,A組數量很少,B組數量很多(顯然這樣分組不合理),這時B的woe就會很小,A組很大,求和的woe也不會小,顯然這樣不合理。比如:

最後我們可以根據每個變數IV值的大小排序去篩選變數。IV越大越要保留。

  • 變數離散化

評分卡模型用的是logistics,基本上都需要將變數離散化後,效果才比較好。

離散化一般有幾種方式:合併和切割。

合併:先把變數分為N份,然後兩兩合併,看是否滿足停止合併條件。

切割:先把變數一分為二,看切割後是否滿足某個條件,滿足則再切割。

而所謂的條件,一般分為兩種,卡方檢驗和信息增益。

  • 啞變數:

當一些變數是非等級的字元串變數時,比如職業ABC,有的人寫成123,其實這樣會有很大的誤差,ABC這3種職業本無關係,但變成123之後,12之間與13之間似乎前者關係更加緊密,對於模型來說(2-1<3-1)。所以我們將其變成啞變數。形如:

代碼部分:

在分類模型中(特別是logistics),對於連續型變數一般都要將其切割(如年齡分為10-20,20-30等區間),而如何去切割並且賦於什麼值,是相對有技術含量的地方。一般而言,會用卡方值或者信息熵去作為切割標準,而切割後會賦於woe值(有的會賦 0 1 2 這類啞變數)。

  • 無監督分箱
  • 1.等頻分箱

def bin_frequency(x,y,n=10): # x為待分箱的變數,y為target變數.n為分箱數量
total = y.count() # 計算總樣本數
bad = y.sum() # 計算壞樣本數
good = y.count()-y.sum() # 計算好樣本數
d1 = pd.DataFrame({x:x,y:y,bucket:pd.qcut(x,n)}) # 用pd.qcut實現等頻分箱
d2 = d1.groupby(bucket,as_index=True) # 按照分箱結果進行分組聚合
d3 = pd.DataFrame(d2.x.min(),columns=[min_bin])
d3[min_bin] = d2.x.min() # 箱體的左邊界
d3[max_bin] = d2.x.max() # 箱體的右邊界
d3[bad] = d2.y.sum() # 每個箱體中壞樣本的數量
d3[total] = d2.y.count() # 每個箱體的總樣本數
d3[bad_rate] = d3[bad]/d3[total] # 每個箱體中壞樣本所佔總樣本數的比例
d3[badattr] = d3[bad]/bad # 每個箱體中壞樣本所佔壞樣本總數的比例
d3[goodattr] = (d3[total] - d3[bad])/good # 每個箱體中好樣本所佔好樣本總數的比例
d3[woe] = np.log(d3[goodattr]/d3[badattr]) # 計算每個箱體的woe值
iv = ((d3[goodattr]-d3[badattr])*d3[woe]).sum() # 計算變數的iv值
d4 = (d3.sort_values(by=min_bin)).reset_index(drop=True) # 對箱體從大到小進行排序
print(分箱結果:)
print(d4)
print(IV值為:)
print(iv)
cut = []
cut.append(float(-inf))
for i in d4.min_bin:
cut.append(i)
cut.append(float(inf))
woe = list(d4[woe].round(3))
return d4,iv,cut,woe

  • 2.等距分箱

def bin_distince(x,y,n=10): # x為待分箱的變數,y為target變數.n為分箱數量
total = y.count() # 計算總樣本數
bad = y.sum() # 計算壞樣本數
good = y.count()-y.sum() # 計算好樣本數
d1 = pd.DataFrame({x:x,y:y,bucket:pd.cut(x,n)}) #利用pd.cut實現等距分箱
d2 = d1.groupby(bucket,as_index=True) # 按照分箱結果進行分組聚合
d3 = pd.DataFrame(d2.x.min(),columns=[min_bin])
d3[min_bin] = d2.x.min() # 箱體的左邊界
d3[max_bin] = d2.x.max() # 箱體的右邊界
d3[bad] = d2.y.sum() # 每個箱體中壞樣本的數量
d3[total] = d2.y.count() # 每個箱體的總樣本數
d3[bad_rate] = d3[bad]/d3[total] # 每個箱體中壞樣本所佔總樣本數的比例
d3[badattr] = d3[bad]/bad # 每個箱體中壞樣本所佔壞樣本總數的比例
d3[goodattr] = (d3[total] - d3[bad])/good # 每個箱體中好樣本所佔好樣本總數的比例
d3[woe] = np.log(d3[goodattr]/d3[badattr]) # 計算每個箱體的woe值
iv = ((d3[goodattr]-d3[badattr])*d3[woe]).sum() # 計算變數的iv值
d4 = (d3.sort_values(by=min_bin)).reset_index(drop=True) # 對箱體從大到小進行排序
print(分箱結果:)
print(d4)
print(IV值為:)
print(iv)
cut = []
cut.append(float(-inf))
for i in d4.min_bin:
cut.append(i)
cut.append(float(inf))
woe = list(d4[woe].round(3))
return d4,iv,cut,woe

  • 3.自定義分箱

def bin_self(x,y,cut): # x為待分箱的變數,y為target變數,cut為自定義的分箱(list)
total = y.count() # 計算總樣本數
bad = y.sum() # 計算壞樣本數
good = y.count()-y.sum() # 計算好樣本數
d1 = pd.DataFrame({x:x,y:y,bucket:pd.cut(x,cut)})
d2 = d1.groupby(bucket,as_index=True) # 按照分箱結果進行分組聚合
d3 = pd.DataFrame(d2.x.min(),columns=[min_bin])
d3[min_bin] = d2.x.min() # 箱體的左邊界
d3[max_bin] = d2.x.max() # 箱體的右邊界
d3[bad] = d2.y.sum() # 每個箱體中壞樣本的數量
d3[total] = d2.y.count() # 每個箱體的總樣本數
d3[bad_rate] = d3[bad]/d3[total] # 每個箱體中壞樣本所佔總樣本數的比例
d3[badattr] = d3[bad]/bad # 每個箱體中壞樣本所佔壞樣本總數的比例
d3[goodattr] = (d3[total] - d3[bad])/good # 每個箱體中好樣本所佔好樣本總數的比例
d3[woe] = np.log(d3[goodattr]/d3[badattr]) # 計算每個箱體的woe值
iv = ((d3[goodattr]-d3[badattr])*d3[woe]).sum() # 計算變數的iv值
d4 = (d3.sort_values(by=min_bin)).reset_index(drop=True) # 對箱體從大到小進行排序
print(分箱結果:)
print(d4)
print(IV值為:)
print(iv)
woe = list(d4[woe].round(3))
return d4,iv,woe

卡方分箱代碼


推薦閱讀:
相關文章