本文引用自:
金融風(fēng)控:信用評(píng)分卡建模流程 - 知乎 (zhihu.com)
在原文的基礎(chǔ)上加上了一部分自己的理解,轉(zhuǎn)載在CSDN上作為保留記錄。
本文涉及到的數(shù)據(jù)集可直接從天池上面下載:
Give Me Some Credit給我一些榮譽(yù)_數(shù)據(jù)集-阿里云天池 (aliyun.com)
正文:
信用評(píng)分卡是一種常用的金融風(fēng)控手段,其主要是通過(guò)建立一套計(jì)分規(guī)則,然后根據(jù)客戶的各項(xiàng)屬性來(lái)匹配計(jì)分規(guī)則,最終得到客戶的風(fēng)險(xiǎn)評(píng)分。根據(jù)評(píng)分結(jié)果來(lái)選擇是否進(jìn)行授信或劃分不同的授信額度和利率,以降低金融交易過(guò)程中的損失風(fēng)險(xiǎn)。信用評(píng)分卡有一套完整的開發(fā)流程,本文將試圖從評(píng)分卡建立所涉及的背景知識(shí),評(píng)分卡建立的基本流程兩個(gè)方面來(lái)從整體上理解信用評(píng)分卡的作用以及建模方法。
1. 信用評(píng)分卡
顧名思義,評(píng)分卡是一張有分?jǐn)?shù)刻度和相應(yīng)閾值的表。對(duì)于一個(gè)客戶,可以根據(jù)他的一系列信息找到對(duì)應(yīng)的分?jǐn)?shù),最終進(jìn)行匯總來(lái)量化這個(gè)客戶將為本次的交易所帶來(lái)的風(fēng)險(xiǎn)。由Fair Isaac公司開發(fā)的FICO系列評(píng)分卡是信用評(píng)分卡的始祖。如圖1所示,F(xiàn)ICO通過(guò)客戶的年齡,住房以及收入情況來(lái)進(jìn)行評(píng)分,每一項(xiàng)指標(biāo)都有一定的閾值范圍,落入不同的閾值范圍就有相應(yīng)的得分,最終的得分是所有指標(biāo)得分的總分。這種評(píng)分手段操作簡(jiǎn)單,易于理解。評(píng)分卡按照不同的使用場(chǎng)景主要分為三類:
1)A卡(Application Card),即申請(qǐng)?jiān)u分卡,主要是用于貸前審批。在此階段,主要利用用戶的外部征信數(shù)據(jù)、資產(chǎn)質(zhì)量數(shù)據(jù)或過(guò)往平臺(tái)表現(xiàn)(復(fù)貸)來(lái)衡量用戶的信用情況。以初步篩選出信用良好的客戶進(jìn)行授信。
2)B卡(Behavior Card),即行為評(píng)分卡,主要是用于貸中階段。即用戶已經(jīng)申請(qǐng)并獲得了相應(yīng)的貸款,用于動(dòng)態(tài)評(píng)估客戶在未來(lái)某一階段的逾期風(fēng)險(xiǎn),進(jìn)而調(diào)整額度或利率等以減少損失
3)C卡(Collection Card),即催收評(píng)分卡,主要是用于貸后管理。即用戶此時(shí)已經(jīng)出現(xiàn)逾期情況,需要制定合理的催收策略以盡可能減少逾期帶來(lái)的損失。此時(shí)根據(jù)C卡評(píng)分來(lái)優(yōu)化貸后管理策略,實(shí)現(xiàn)催收資源的合理配置
圖1 FICO評(píng)分卡
類似FICO這種靜態(tài)的評(píng)分卡最大的優(yōu)點(diǎn)在于操作簡(jiǎn)單,可解釋性強(qiáng)。但隨著時(shí)間的推移,目標(biāo)客群會(huì)不斷發(fā)生變化,這種靜態(tài)的方式難以滿足需求。于是,基于機(jī)器學(xué)習(xí)模型的信用評(píng)分卡展現(xiàn)出了更大的潛力。其能夠根據(jù)數(shù)據(jù)的變化去動(dòng)態(tài)調(diào)整不同特征的權(quán)重,從而不斷迭代以適應(yīng)新的數(shù)據(jù)模式。在風(fēng)控領(lǐng)域,為了提高信用評(píng)分卡的可解釋性,通常采用邏輯回歸模型來(lái)進(jìn)行評(píng)分卡的建模。在下一節(jié)中,將使用Kaggle上的Give me credit card數(shù)據(jù)來(lái)從0到1建立一個(gè)信用評(píng)分卡,從中梳理出評(píng)分卡的常規(guī)建模流程。在建模期間也會(huì)穿插介紹其中涉及的一些重要概念,理解這些概念背后的原理才能明白做這一步的含義是什么。
2. 信用評(píng)分卡建模流程
2.1 探索性數(shù)據(jù)分析(EDA)
EDA主要是利用各種統(tǒng)計(jì)分析的手段來(lái)從整體上了解數(shù)據(jù)的情況,包括數(shù)據(jù)的構(gòu)成,數(shù)據(jù)的質(zhì)量,數(shù)據(jù)的含義等。以便后續(xù)針對(duì)特定的問題制定合理的數(shù)據(jù)預(yù)處理方案,完成特征工程的工作
1. 特征釋義
本次采用的數(shù)據(jù)集包括12個(gè)特征,其中有效特征為11個(gè)(一個(gè)Uname0特征)。各個(gè)特征的具體含義如下。
- SeriousDlqin2yrs:超過(guò)90天或更糟的逾期拖欠,是用戶的標(biāo)簽,0,1分別表示未逾期和逾期
- RevolvingUtilizationOfUnsecuredLines:除了房貸車貸之外的信用卡賬面金額(即貸款金額)/信用卡總額度
- age:貸款人年齡
- NumberOfTime30-59DaysPastDueNotWorse:借款人逾期30-59天的次數(shù)
- DebtRatio:負(fù)債比率,每月債務(wù)、贍養(yǎng)費(fèi)、生活費(fèi)/每月總收入
- MonthlyIncome:月收入
- NumberOfOpenCreditLinesAndLoans:開放式信貸和貸款數(shù)量,開放式貸款(分期付款如汽車貸款或抵押貸款)和信貸(如信用卡)的數(shù)量
- NumberOfTimes90DaysLate:借款者有90天或更高逾期的次數(shù)
- NumberRealEstateLoansOrLines:包括房屋凈值信貸額度在內(nèi)的抵押貸款和房地產(chǎn)貸款數(shù)量
- NumberOfTime60-89DaysPastDueNotWorse:借款人逾期60-89天的次數(shù)
- NumberOfDependents:不包括本人在內(nèi)的家屬數(shù)量
2. 數(shù)據(jù)基本情況
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
df_train = pd.read_csv("./data/cs-training.csv")
df_test = pd.read_csv("./data/cs-test.csv")
df_all = pd.concat([df_train,df_test])
print("train size:",len(df_train))
print("test size:",len(df_test))
print(df_all.info())
數(shù)據(jù)集總共包含251503條數(shù)據(jù),其中訓(xùn)練集有150000條數(shù)據(jù),測(cè)試集有101503條數(shù)據(jù)。MonthlyIncome 和 NumberOfDependents有缺失值,由于缺失并不嚴(yán)重,因此予以保留,后續(xù)進(jìn)行插補(bǔ)。
3. 異常值檢測(cè)
這里采用3西格瑪原則從各個(gè)特征中檢測(cè)異常值并進(jìn)行統(tǒng)計(jì),以了解數(shù)據(jù)中異常值的情況
#異常檢測(cè)
def review_outlier(x,lower,upper):
'''
根據(jù)3-西格瑪方法檢測(cè)出特征中的異常值
'''
if x < lower or x > upper:
return True
return False
df_outlier_train = df_train.copy()
k = 3.0
for fea in df_outlier_train.columns:
lower = df_outlier_train[fea].mean() - k*df_outlier_train[fea].std()
upper = df_outlier_train[fea].mean() + k*df_outlier_train[fea].std()
outlier = df_outlier_train[fea]\
.apply(review_outlier,args=(lower,upper))
print("{} 異常值數(shù)量:{}".format(fea,outlier.sum()))
NumberOfOpenCreditLinesAndLoans以及NumberRealEstateLoansOrLines的異常值數(shù)量較大。從數(shù)據(jù)的角度而言這兩個(gè)特征可以考慮剔除或刪除有異常的數(shù)據(jù),但從業(yè)務(wù)角度而言,這兩個(gè)特征與逾期風(fēng)險(xiǎn)可能存在較大的關(guān)聯(lián),所以最終還是保留這兩個(gè)特征。
4. 描述性統(tǒng)計(jì)
sns.countplot(x='SeriousDlqin2yrs',data=df_train)
從標(biāo)簽的分布來(lái)看,樣本中的好客戶占比明顯高于壞客戶,意味著后續(xù)需要進(jìn)行數(shù)據(jù)的平衡,避免模型過(guò)度傾向于將樣本預(yù)測(cè)為好客戶。
#對(duì)數(shù)據(jù)中的好壞客戶的年齡分布進(jìn)行統(tǒng)計(jì)
bad = df_train[df_train['SeriousDlqin2yrs']==1].index
good = df_train[df_train['SeriousDlqin2yrs']==0].index
fig,ax = plt.subplots(2,1,figsize=[6,6])
fig.subplots_adjust(hspace=0.5)
sns.distplot(df_train.loc[bad,'age'],ax=ax[0])
ax[0].set_title("bad customer")
sns.distplot(df_train.loc[good,'age'],ax=ax[1])
ax[1].set_title("good customer")
print("壞客戶年齡統(tǒng)計(jì)\n",df_train.loc[bad,'age'].describe())
print("好客戶年齡統(tǒng)計(jì)\n",df_train.loc[good,'age'].describe())
從頻率分布圖的形狀來(lái)看,好壞客戶的年齡分布整體上都符合正態(tài)分布,符合統(tǒng)計(jì)學(xué)的概念。其中,壞客戶和好客戶的年齡均值分別為45.9和52.8,壞客戶的年齡略低于好客戶的年齡。好客戶中年齡最小值為0歲,年齡最大值為109歲,這不太符合常規(guī)的借貸業(yè)務(wù)客群特征,考慮可能是異常值,后續(xù)需要進(jìn)行處理。
5. 變量顯著性檢驗(yàn)
ps: 這里涉及到變量之間檢驗(yàn)方法
該問題預(yù)測(cè)變量X是每個(gè)特征的值,反應(yīng)變量Y是"bad",”good”類別,這里做兩樣本T檢驗(yàn)的目的是為了觀察類別為bad的特征和類別為good的特征是否為有顯著差異,而兩樣本T檢驗(yàn)是為了判別兩類別均值是否相等。對(duì)于分類問題來(lái)說(shuō),我們可以粗略的認(rèn)為分類后的樣本均值距離越遠(yuǎn)分的越好(類間距離)所以,T檢驗(yàn)在該問題中可以用來(lái)判斷某一特征對(duì)于分類“bad”,"good"是否有顯著差異(有顯著差異的話說(shuō)明該特征對(duì)于分類是有正向作用的)
下面這個(gè)帖子詳細(xì)講述了T檢驗(yàn)的用法。
雙樣本T檢驗(yàn)——機(jī)器學(xué)習(xí)特征工程相關(guān)性分析實(shí)戰(zhàn) - 知乎
這里主要是想觀察同一個(gè)特征在不同標(biāo)簽的客戶群體中的差異,若有顯著差異,則表明該特征與客戶是否逾期有顯著的相關(guān)性,后續(xù)建模需要保留這部分特征,反之,可以進(jìn)行特征過(guò)濾,初步篩選掉一些不重要的特征,降低模型的復(fù)雜度。這里采用scipy庫(kù)中的ttest_ind來(lái)檢驗(yàn)特征的在不同客群中的差異,通過(guò)Levene來(lái)確定方差齊性。定義p小于0.001時(shí)分布具有顯著差異。
#變量顯著性檢驗(yàn)
from scipy.stats import levene,ttest_ind
bad = df_train[df_train['SeriousDlqin2yrs']==1].index
good = df_train[df_train['SeriousDlqin2yrs']==0].index
fea_pvalue = {}
for fea in df_train.columns[2:]:
p_values = {}
_, pvalue_l = levene(train_x.loc[bad,fea], train_x.loc[good,fea])
# 當(dāng)p>0.05時(shí)不能拒絕原假設(shè),即認(rèn)為方差對(duì)齊
if pvalue_l > 0.05:
_, p_values = ttest_ind(train_x.loc[bad,fea], train_x.loc[good,fea], equal_var=True)
fea_pvalue[fea] = p_values
else:
_, p_values = ttest_ind(train_x.loc[bad,fea], train_x.loc[good,fea], equal_var=False)
fea_pvalue[fea] = p_values
fea_pvalue = pd.DataFrame(fea_pvalue,index=[0]).T.rename(columns={0:'p-value'})
fea_pvalue
最終所有特征的p值均小于0.001,表示都具有顯著差異,因此后續(xù)所有特征都可以考慮進(jìn)入模型。
2.2 數(shù)據(jù)清洗與預(yù)處理
經(jīng)過(guò)前一步的探索性數(shù)據(jù)分析后,我們發(fā)現(xiàn)數(shù)據(jù)中存在著缺失值和異常值,在數(shù)據(jù)預(yù)處理階段需要進(jìn)行處理。鑒于變量顯著性檢驗(yàn)中的結(jié)果,即所有特征都與逾期風(fēng)險(xiǎn)有顯著的相關(guān)性,因此對(duì)于與缺失和異常值的處理均不采用刪除特征的方式來(lái)進(jìn)行。對(duì)于異常值,先將其替換為缺失值,最后再與缺失值進(jìn)行統(tǒng)一的插補(bǔ)。對(duì)于數(shù)據(jù)不平衡問題,可以通過(guò)對(duì)少數(shù)樣本進(jìn)行增采樣或?qū)Χ鄶?shù)樣本進(jìn)行減采樣的方式來(lái)保障類別的平衡。當(dāng)然,這里也能夠在模型訓(xùn)練階段為不同類別的樣本制定不同的權(quán)重,從而使得模型不會(huì)過(guò)度偏向占比較大的類別。這是根據(jù)前面探索性分析后制定的初步數(shù)據(jù)預(yù)處理方案,主要是針對(duì)數(shù)據(jù)質(zhì)量的問題。在風(fēng)控建模中還需要涉及到數(shù)據(jù)分箱,WOE編碼,變量篩選等過(guò)程,主要是提升特征的表達(dá)能力,解決的是模型性能的問題,這些相關(guān)的數(shù)據(jù)處理細(xì)節(jié)將在后面逐步展開
1. 數(shù)據(jù)清洗
刪除數(shù)據(jù)中的無(wú)效列名
df_train = df_train.drop(columns=['Unnamed: 0'])
df_test = df_test.drop(columns=['Unnamed: 0'])
from sklearn.model_selection import train_test_split
一般在進(jìn)行建模之前,都需要將數(shù)據(jù)拆分成三份,即訓(xùn)練集,測(cè)試集和驗(yàn)證集。訓(xùn)練集是用于模型的訓(xùn)練擬合。驗(yàn)證集是在模型訓(xùn)練階段與訓(xùn)練集配合使用來(lái)選擇一些超參數(shù)或制定優(yōu)化模型的策略。測(cè)試集主要是為了檢驗(yàn)?zāi)P偷臄M合程度,泛化能力等。一般來(lái)講,需要將數(shù)據(jù)按照時(shí)間來(lái)進(jìn)行劃分子集。比如有2020-01-01到2022-01-01的數(shù)據(jù),那么可以選擇最后一年的數(shù)據(jù)來(lái)作為驗(yàn)證集和測(cè)試集,其中兩個(gè)子集各占半年。而第一年的數(shù)據(jù)作為訓(xùn)練集來(lái)訓(xùn)練模型。這樣能夠檢驗(yàn)?zāi)P偷目鐣r(shí)間穩(wěn)定性。由于我們案例中使用的數(shù)據(jù)沒有時(shí)間的標(biāo)識(shí),且測(cè)試集沒有標(biāo)簽,所以這里將訓(xùn)練集隨機(jī)拆分(7:3)成訓(xùn)練集和驗(yàn)證集,以模擬這一場(chǎng)景。
from sklearn.model_selection import train_test_split
#拆分?jǐn)?shù)據(jù),將訓(xùn)練集拆分成訓(xùn)練數(shù)據(jù)和驗(yàn)證數(shù)據(jù),以檢測(cè)特征和模型的穩(wěn)定性等指標(biāo)
train,valid = train_test_split(df_train,test_size=0.3,random_state=0)
train.reset_index(drop=True,inplace=True)
valid.reset_index(drop=True,inplace=True)
print("train size:{}".format(len(train)))
print("valid size:{}".format(len(valid)))
print("test size:{}".format(len(df_test)))
2. 異常值過(guò)濾和缺失插補(bǔ)
對(duì)于異常值的處理方法主要有三種,一是直接刪除,二是替換為缺失值后進(jìn)行插補(bǔ),三是通過(guò)分箱將異常值單獨(dú)作為一個(gè)分組看待。在這里以第二種方法進(jìn)行處理,即把異常值視為缺失值。
k = 3.0
#使用3西格瑪原則檢測(cè)異常值,各個(gè)特征的均值和標(biāo)準(zhǔn)差以訓(xùn)練集計(jì)算,驗(yàn)證集和測(cè)試集直接使用
for fea in train.columns:
if fea=='SeriousDlqin2yrs':
continue
lower = train[fea].mean() - k*train[fea].std()
upper = train[fea].mean() + k*train[fea].std()
if_outlier_train = train[fea].apply(review_outlier,args=(lower,upper))
if_outlier_val = valid[fea].apply(review_outlier,args=(lower,upper))
if_outlier_test = df_test[fea].apply(review_outlier,args=(lower,upper))
out_index_train = np.where(if_outlier_train)[0]
out_index_val = np.where(if_outlier_val)[0]
out_index_test = np.where(if_outlier_test)[0]
#替換為空值
train.loc[out_index_train,fea] = np.nan
valid.loc[out_index_val,fea] = np.nan
df_test.loc[out_index_test,fea] = np.nan
數(shù)據(jù)插補(bǔ)一般選用均值或中位數(shù)(連續(xù)變量),此外,根據(jù)3西格瑪原則,可以通過(guò)生成均值加減三倍標(biāo)準(zhǔn)差范圍內(nèi)的隨機(jī)數(shù)進(jìn)行插補(bǔ),但由于這份數(shù)據(jù)集中特征的標(biāo)準(zhǔn)差很大,數(shù)據(jù)分布比較分散,所以生成的隨機(jī)數(shù)可能會(huì)是一個(gè)異常值(比如年齡為負(fù)數(shù)),因此這里以中位數(shù)來(lái)插補(bǔ)。注意,中位數(shù)是由訓(xùn)練集計(jì)算出來(lái)的,驗(yàn)證集和測(cè)試集直接使用。
#以特征的中位數(shù)插補(bǔ)數(shù)據(jù)
median = train.median()
train.fillna(median,inplace=True)
valid.fillna(median,inplace=True)
df_test.fillna(median,inplace=True)
print(train.info())
3. 特征分箱
在風(fēng)控建模過(guò)程中常常需要對(duì)變量進(jìn)行分箱處理,主要是將連變量進(jìn)行離散化處理形成類別變量,類別變量可以進(jìn)行適當(dāng)?shù)暮喜ⅰ7窒涞暮诵哪繕?biāo)就是為了提升模型整體的穩(wěn)定性。比如將異常值和缺失值單獨(dú)作為一個(gè)分箱,使得模型對(duì)這些值不太敏感。另一方面,對(duì)于LR這種線性模型,分箱也能夠使得特征帶有一些非線性的特性,從而提升模型的非線性表達(dá)能力。在風(fēng)控中常用的分箱方法有等頻分箱,等距分箱,聚類分箱,卡方分箱,Best-KS分箱等。更加詳細(xì)的討論可以參照之前寫的文章風(fēng)控建模中的分箱方法——原理與代碼實(shí)現(xiàn)。這里使用toda庫(kù)來(lái)實(shí)現(xiàn)對(duì)特征進(jìn)行卡方分箱。toad是由厚本金融風(fēng)控團(tuán)隊(duì)內(nèi)部孵化,后開源并堅(jiān)持維護(hù)的標(biāo)準(zhǔn)化評(píng)分卡庫(kù)。其功能全面、性能穩(wěn)健、運(yùn)行速度快,是風(fēng)控建模中常使用的一個(gè)模型開發(fā)庫(kù)。有關(guān)toad庫(kù)的基本使用可以參考下面幾篇文章。
Zain Mei:Toad | Pyhon評(píng)分卡工具輕松實(shí)現(xiàn)風(fēng)控模型開發(fā)168 贊同 · 32 評(píng)論文章?編輯
評(píng)分卡建模Toad庫(kù)的使用_Labryant的博客-CSDN博客_python toad庫(kù)?blog.csdn.net/lc434699300/article/details/105232380?編輯
promise:信貸評(píng)分卡建模庫(kù)Toad簡(jiǎn)單應(yīng)用12 贊同 · 1 評(píng)論文章?編輯
import toad
combiner = toad.transform.Combiner()
#以訓(xùn)練集擬合得出分箱節(jié)點(diǎn)
combiner.fit(train,train["SeriousDlqin2yrs"],method='chi',min_samples=0.05,exclude=["SeriousDlqin2yrs"])
bins = combiner.export()
bins
#按照生成的分箱節(jié)點(diǎn)對(duì)數(shù)據(jù)進(jìn)行分箱處理
train_bin = combiner.transform(train)
valid_bin = combiner.transform(valid)
test_bin = combiner.transform(df_test)
test_bin
分箱轉(zhuǎn)換后每一個(gè)特征的值都會(huì)被分配一個(gè)編號(hào),表示該特征落在某一個(gè)分箱中。
分箱的效果可以通過(guò)壞客戶占比的單調(diào)性來(lái)進(jìn)行初步判斷以及作為分箱調(diào)整的依據(jù)。這里壞客戶占比的單調(diào)性是指在每一個(gè)分箱中壞客戶的占比是否隨著分箱的取值范圍的變化而產(chǎn)生單調(diào)變化,具體的變化方向需要結(jié)合業(yè)務(wù)知識(shí)來(lái)考量。這里主要是考慮到業(yè)務(wù)的可解釋性問題,比如對(duì)于負(fù)債比,理論上負(fù)債比越高那么客戶的逾期風(fēng)險(xiǎn)也就越高,也就是說(shuō),在負(fù)債比較高的分箱中壞客戶的占比應(yīng)該是更大的。下面通過(guò)繪制Bivar圖來(lái)觀察每個(gè)特征分箱后的情況,以便進(jìn)行適當(dāng)?shù)姆窒湔{(diào)整。
from toad.plot import badrate_plot,bin_plot
for fea in train_bin.columns:
if fea == 'SeriousDlqin2yrs':
continue
bin_plot(frame=train_bin,x=fea,target='SeriousDlqin2yrs',iv=False)
上面展示了幾個(gè)特征的Bivar圖示例,除了DebtRatio外,其他特征基本上滿足單調(diào)性的要求,其變化方向也與業(yè)務(wù)上的理解比較接近,比如NumberOfTime30-59DaysPastDueNotWorse(逾期30-59天的次數(shù))增加時(shí),客戶最終逾期的風(fēng)險(xiǎn)也在增加。對(duì)于DebtRatio,可以通過(guò)手動(dòng)調(diào)整分箱節(jié)點(diǎn)進(jìn)行分箱合并,來(lái)保障一定的單調(diào)性。從圖中可以看到第四個(gè)分箱壞客戶占比下降,不符合整體上升的趨勢(shì),因此將其合并到第三個(gè)分箱中。
#DebtRatio原先的分箱節(jié)點(diǎn),[0.354411397, 0.49562442100000004, 3.61878453]
#重新設(shè)置分箱規(guī)則
adj_bin = {'DebtRatio': [0.354411397,0.49562442100000004]}
combiner.set_rules(adj_bin)
#根據(jù)新規(guī)則重新分箱
train_bin = combiner.transform(train)
valid_bin = combiner.transform(valid)
test_bin = combiner.transform(df_test)
bin_plot(frame=train_bin,x='DebtRatio',target='SeriousDlqin2yrs',iv=False)
重新分箱后可以看到DebtRatio也能夠呈現(xiàn)出單調(diào)性,隨著負(fù)債比的增加,客戶的逾期風(fēng)險(xiǎn)也在增加,符合業(yè)務(wù)上的理解。此外,在實(shí)際中我們還需要觀察一個(gè)特征分箱在訓(xùn)練集以及驗(yàn)證集/測(cè)試集中的壞客戶占比情況以確定分箱是否具有跨時(shí)間穩(wěn)定性。若分箱在訓(xùn)練集上的壞客戶占比與驗(yàn)證集/測(cè)試集上同一個(gè)分箱的壞客戶占比差異很大,訓(xùn)練出來(lái)的模型不穩(wěn)定且易過(guò)擬合,則需要考慮進(jìn)行重新分箱。以DebtRatio的負(fù)樣本關(guān)聯(lián)圖來(lái)進(jìn)行說(shuō)明
#標(biāo)識(shí)樣本是訓(xùn)練樣本還是驗(yàn)證樣本
train_bin['sample_type'] = ['train'] * len(train_bin)
valid_bin['sample_type'] = ['valid'] * len(valid_bin)
#繪制負(fù)樣本關(guān)聯(lián)圖
badrate_plot(frame=pd.concat([train_bin,valid_bin]),x='sample_type',target='SeriousDlqin2yrs',by='DebtRatio')
train_bin= train_bin.drop(columns=['sample_type'])
valid_bin = valid_bin.drop(columns=['sample_type'])
上圖每一條線代表的是一個(gè)分箱在兩個(gè)數(shù)據(jù)集中壞客戶占比的連線。這里三個(gè)分箱(三條線)沒有出現(xiàn)交叉,表明同一個(gè)分箱中壞客戶占比在兩個(gè)數(shù)據(jù)集上的差異不大。若出現(xiàn)交叉,假設(shè)上圖的0和1出現(xiàn)交叉,意味著這兩個(gè)分箱中壞客戶占比在不同的數(shù)據(jù)集中差異很大,可以考慮將0和1進(jìn)行合并。使得分箱中的壞客戶占比在訓(xùn)練集和驗(yàn)證集上較為接近。
特征分箱后需要面臨的一個(gè)問題是分箱的編碼。前面也展示過(guò)分箱后每一個(gè)特征的值都會(huì)被賦予一個(gè)分箱的編號(hào)。這個(gè)編號(hào)只是對(duì)分箱的一種簡(jiǎn)單編碼形式。這種編碼無(wú)法定量地反映分箱內(nèi)的樣本占比情況。我們習(xí)慣以線性的方式來(lái)判斷變量的作用,即x越大時(shí),y就越大或越小。WOE編碼就是通過(guò)對(duì)比分箱內(nèi)的壞好客戶的占比跟總體的壞好客戶占比來(lái)衡量分箱對(duì)于預(yù)測(cè)結(jié)果的“貢獻(xiàn)”。對(duì)于這種“貢獻(xiàn)”,可以這么去理解。我們?yōu)榱祟A(yù)測(cè)樣本是好客戶還是壞客戶,需要知道一些信息或者說(shuō)收集一些證據(jù)(特征),那么當(dāng)這些信息非常有用時(shí)(特征的一個(gè)分箱內(nèi)幾乎全是壞客戶),也就是當(dāng)樣本的該特征落在這個(gè)分箱時(shí),我們能夠很有把握地認(rèn)為該樣本是壞客戶。這個(gè)證據(jù)顯然非常重要,那就需要為它賦予一個(gè)更大的權(quán)重,且這個(gè)權(quán)重對(duì)于預(yù)測(cè)樣本為壞客戶起到正向作用??偟膩?lái)說(shuō),WOE的絕對(duì)值越大,表示分箱內(nèi)的樣本分布與總體的樣本分布差異越大,我們能夠從分箱的角度來(lái)區(qū)分好壞樣本。而正負(fù)則表示這種差異的方向,即更容易認(rèn)為分箱內(nèi)的樣本是好樣本還是壞樣本。下面是每個(gè)分箱的WOE值的計(jì)算方法,有興趣進(jìn)一步了解可以參照之前的文章風(fēng)控建模指標(biāo)PSI,IV和WOE理解。使用Toad庫(kù)的WOETransformer()可以很方便地將分箱后的數(shù)據(jù)轉(zhuǎn)換為WOE編碼。
#對(duì)分箱結(jié)果進(jìn)行WOE編碼
woe_t = toad.transform.WOETransformer()
train_woe = woe_t.fit_transform(train_bin,train_bin['SeriousDlqin2yrs'],exclude=["SeriousDlqin2yrs"])
valid_woe = woe_t.transform(valid_bin)
test_woe = woe_t.transform(test_bin)
train_woe
4. 特征篩選
一般而言,我們?cè)诮G捌诟鶕?jù)業(yè)務(wù)理解以及其他先驗(yàn)知識(shí)或現(xiàn)有數(shù)據(jù)情況可能選擇了非常多的特征。但并不意味這些特征都是需要進(jìn)入模型訓(xùn)練。一方面這些特征有些可能并沒有重要的業(yè)務(wù)指導(dǎo)意義,另一方面,當(dāng)模型納入過(guò)多特征時(shí),容易使得模型變得復(fù)雜,有出現(xiàn)過(guò)擬合的風(fēng)險(xiǎn)。當(dāng)然,本案例中的特征數(shù)量不多,且基本上都有重要的業(yè)務(wù)含義,基本不涉及特征篩選。但為了整個(gè)建模流程能夠完整,下面還是對(duì)特征進(jìn)行篩選,重點(diǎn)在于理解篩選的流程以及背后的含義。
在建模的過(guò)程中,對(duì)于一個(gè)特征的考量主要考慮幾個(gè)方面,即特征的穩(wěn)定性(細(xì)微變化不應(yīng)當(dāng)引起預(yù)測(cè)結(jié)果的顯著變化),特征的可解釋性(符合業(yè)務(wù)理解),特征的預(yù)測(cè)能力(有效區(qū)分好壞客戶)。所以,在進(jìn)行特征篩選的過(guò)程中同樣是遵循這幾項(xiàng)原則,有目的地篩選最終用于模型訓(xùn)練的特征。在本案例中,特征的可解釋性基本上是滿足的,每一個(gè)特征的含義在特征解釋部分已經(jīng)給出。后面主要是從特征的穩(wěn)定性以及特征的預(yù)測(cè)能力兩個(gè)方面來(lái)進(jìn)行篩選。
1)通過(guò)IV(Information Value)值確定特征的預(yù)測(cè)能力
經(jīng)過(guò)WOE編碼后的特征被賦予了一個(gè)代表特征預(yù)測(cè)能力的權(quán)重,即WOE值(各個(gè)分箱WOE值的求和)。但一般我們并不根據(jù)WOE來(lái)進(jìn)行特征篩選。一個(gè)重要的原因是WOE值并不考慮分箱內(nèi)樣本在總體樣本中的占比情況。也就是說(shuō),當(dāng)一個(gè)分箱的樣本占比很低時(shí),盡管其WOE值很高(里面大部分是壞客戶或好客戶),但本身樣本落在這個(gè)分箱的概率就非常小,所以該分箱對(duì)于整體樣本的預(yù)測(cè)貢獻(xiàn)是不大的。而IV值彌補(bǔ)了這一缺陷,其是分箱WOE值的加權(quán)求和。這里的權(quán)重就是分箱內(nèi)壞客戶以及好客戶在各自總體中的占比情況,也就是考慮了前面所提到的分箱中樣本占總體的情況。當(dāng)分箱中的樣本很少時(shí),這個(gè)權(quán)重也會(huì)非常小,此時(shí)就算分箱的WOE值很高,最終加權(quán)求和的結(jié)果也會(huì)很低。下面是IV的計(jì)算公式以及不同取值的業(yè)務(wù)含義。
下面使用Toad的quality()函數(shù)來(lái)計(jì)算每個(gè)特征的IV值,并過(guò)濾掉IV小于0.1的特征。
IV = toad.quality(train_woe,'SeriousDlqin2yrs',iv_only=True).loc[:,'iv'].round(2)
IV
可以看到RevolvingUtilizationOfUnsecuredLines,NumberOfTimes90DaysLate,NumberOfTime30-59DaysPastDueNotWorse,age四個(gè)特征的IV值大于0.1,因此予以保留。
2)通過(guò)PSI(Population Stability Index)衡量特征的跨時(shí)間穩(wěn)定性
在風(fēng)控建模中,穩(wěn)定性甚至比準(zhǔn)確性更重要。這里的穩(wěn)定性是模型評(píng)分或特征分箱在不同的數(shù)據(jù)集(一般認(rèn)為是訓(xùn)練數(shù)據(jù)和跨時(shí)間驗(yàn)證集)上的分布差異。PSI是衡量模型或特征跨時(shí)間穩(wěn)定性的一個(gè)重要指標(biāo)。在機(jī)器學(xué)習(xí)建模的過(guò)程中,一個(gè)基本的假設(shè)是“歷史樣本的分布與未來(lái)樣本的分布一致”,這樣我們才有可能利用歷史樣本來(lái)訓(xùn)練模型并應(yīng)用在未來(lái)的樣本上。但是,隨著時(shí)間的推移,客群的屬性難免會(huì)發(fā)生一些細(xì)微的變化。如果一個(gè)模型或特征是穩(wěn)定的,那么這種細(xì)微的變化不應(yīng)當(dāng)引起模型的評(píng)分或特征的人群分布產(chǎn)生太大的變化。所以,當(dāng)模型評(píng)分或者特征分箱中的樣本占比分布在訓(xùn)練樣本上的預(yù)期分布跟驗(yàn)證數(shù)據(jù)上的實(shí)際分布差異小,則認(rèn)為模型或特征足夠穩(wěn)定,其能夠在不同的數(shù)據(jù)集上有相似的表現(xiàn)。我們將隨機(jī)拆分出來(lái)的驗(yàn)證集假設(shè)為是跨時(shí)間的樣本。特征的PSI就是要衡量一個(gè)特征在訓(xùn)練集和驗(yàn)證集上的分布差異,如果這種差異很?。≒SI?。?,則表明這個(gè)特征是穩(wěn)定的,不會(huì)因?yàn)闀r(shí)間的推移(特征發(fā)生細(xì)微變化)而使得人群產(chǎn)生非常大的變化。有關(guān)PSI的詳細(xì)討論可以參照之前的文章風(fēng)控建模指標(biāo)PSI,IV和WOE理解。下面是PSI的計(jì)算公式以及不同取值的業(yè)務(wù)含義
使用Toda的PSI()函數(shù)可以很方便地計(jì)算特征的PSI值。根據(jù)PSI大于0.25來(lái)過(guò)濾不穩(wěn)定的特征。
#計(jì)算PSI
psi = toad.metrics.PSI(train_woe,valid_woe)
psi
可以看到前面根據(jù)IV值篩選出的四個(gè)特征的PSI都小于0.1,所以不需要進(jìn)一步過(guò)濾。
2.3 評(píng)分卡建模
1. 生成最終的數(shù)據(jù)集
根據(jù)數(shù)據(jù)預(yù)處理階段得到的結(jié)果,我們完成了對(duì)數(shù)據(jù)的異常過(guò)濾和缺失數(shù)據(jù)插補(bǔ),完成了特征的分箱,WOE編碼以及根據(jù)IV和PSI進(jìn)行特征的篩選。最終模型使用四個(gè)特征來(lái)進(jìn)行訓(xùn)練,包括RevolvingUtilizationOfUnsecuredLines,NumberOfTimes90DaysLate,NumberOfTime30-59DaysPastDueNotWorse,age這四個(gè)特征。根據(jù)這個(gè)結(jié)果,確定最終用于模型訓(xùn)練和驗(yàn)證的數(shù)據(jù)集。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score,roc_curve
import xgboost as xgb
#確定最終用于模型訓(xùn)練和驗(yàn)證的數(shù)據(jù)集
train_set = train_woe[['RevolvingUtilizationOfUnsecuredLines',
'NumberOfTimes90DaysLate','NumberOfTime30-59DaysPastDueNotWorse','age','SeriousDlqin2yrs']]
valid_set = valid_woe[train_set.columns]
test_set = test_woe[train_set.columns]
#特征以及目標(biāo)變量
fea_lst = ['RevolvingUtilizationOfUnsecuredLines', 'NumberOfTimes90DaysLate','NumberOfTime30-59DaysPastDueNotWorse','age']
target = 'SeriousDlqin2yrs'
2. 模型選擇
機(jī)器學(xué)習(xí)模型有很多,盡管目前XGBoost,神經(jīng)網(wǎng)絡(luò)等模型效果更好。但在風(fēng)控建模中最常用的還是邏輯回歸模型。主要是因?yàn)檫壿嫽貧w模型簡(jiǎn)單易用,可解釋性強(qiáng)。當(dāng)模型出現(xiàn)問題時(shí),能夠更加容易找到原因,各個(gè)特征的系數(shù)也能夠結(jié)合業(yè)務(wù)知識(shí)來(lái)進(jìn)行評(píng)估和解釋。然而,邏輯回歸對(duì)于非線性問題的處理能力較差。所以,在建模階段可以同時(shí)建立一個(gè)更為復(fù)雜的輔助模型,如XGBoost。通過(guò)觀察邏輯回歸和輔助模型的模型表現(xiàn),來(lái)進(jìn)一步調(diào)整用于邏輯回歸訓(xùn)練的特征。比如,假設(shè)下圖是XGBoost生成的一個(gè)決策過(guò)程。那么客戶年齡以及負(fù)債比就可在組合成一個(gè)新的特征。如年齡大于25歲且負(fù)債比大于1作為一個(gè)組合特征,若客戶滿足這一情況則標(biāo)記該特征為1,否則標(biāo)記為0。同樣地,年齡大于25歲且負(fù)債比小于1作為一個(gè)組合特征,若客戶滿足這一情況則標(biāo)記該特征為1,否則標(biāo)記為0。這就根據(jù)XGBoost這種復(fù)雜模型生成的一些規(guī)則來(lái)交叉組合形成一些新的特征,從而使得邏輯回歸模型也能夠像XGBoost一樣具有處理非線性問題的能力,提升邏輯回歸的性能
3. 模型評(píng)估
?
在我們的評(píng)分卡建模中,最終使用AUC和KS來(lái)進(jìn)行模型的評(píng)估。
3. 預(yù)訓(xùn)練模型
預(yù)訓(xùn)練模型的作用在于優(yōu)化和調(diào)整用于模型訓(xùn)練的特征或模型超參數(shù)。即利用訓(xùn)練集進(jìn)行模型訓(xùn)練,在驗(yàn)證集上進(jìn)行一系列的評(píng)估。根據(jù)評(píng)估結(jié)果選擇最佳的模型超參數(shù)或重新去調(diào)整特征。下面將通過(guò)建立輔助模型XGBoot來(lái)觀察是否有必要進(jìn)行特征的交叉。另一方面,通過(guò)正向和方向訓(xùn)練驗(yàn)證的方法來(lái)觀察是否需要對(duì)特征進(jìn)行調(diào)整。這里正向的意思是以訓(xùn)練集訓(xùn)練模型,以驗(yàn)證集評(píng)估模型,反向則是反過(guò)來(lái),以驗(yàn)證集來(lái)訓(xùn)練模型。通過(guò)觀察正向和反向的評(píng)估結(jié)果,如果差異較大,則可能代表模型的穩(wěn)定性很差或訓(xùn)練集和驗(yàn)證集的差異很大,需要對(duì)特征進(jìn)一步調(diào)整優(yōu)化以過(guò)濾掉一些不穩(wěn)定的特征或重新制定劃分?jǐn)?shù)據(jù)集的策略。
定義邏輯回歸模型
def lr_model(x, y, valx, valy, C):
model = LogisticRegression(C=C, class_weight='balanced')
model.fit(x,y)
y_pred = model.predict_proba(x)[:,1]
fpr_dev,tpr_dev,_ = roc_curve(y, y_pred)
train_ks = abs(fpr_dev - tpr_dev).max()
dev_auc = roc_auc_score(y_score=y_pred,y_true=y)
print('train_ks : ', train_ks)
y_pred = model.predict_proba(valx)[:,1]
fpr_val,tpr_val,_ = roc_curve(valy, y_pred)
val_ks = abs(fpr_val - tpr_val).max()
val_auc = roc_auc_score(y_score=y_pred,y_true=valy)
print('val_ks : ', val_ks)
plt.plot(fpr_dev, tpr_dev, label='dev:{:.3f}'.format(dev_auc))
plt.plot(fpr_val, tpr_val, label='val:{:.3f}'.format(val_auc))
plt.plot([0,1], [0,1], 'k--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC Curve')
plt.legend(loc='best')
plt.show()
定義XGBoost模型
def xgb_model(x, y, valx, valy):
model = xgb.XGBClassifier(learning_rate=0.05,
n_estimators=400,
max_depth=2,
min_child_weight=1,
subsample=1,
nthread=-1,
scale_pos_weight=1,
random_state=1,
n_jobs=-1,
reg_lambda=300,
use_label_encoder=False)
model.fit(x, y,eval_metric='logloss')
y_pred = model.predict_proba(x)[:,1]
fpr_dev,tpr_dev,_ = roc_curve(y, y_pred)
train_ks = abs(fpr_dev - tpr_dev).max()
dev_auc = roc_auc_score(y_score=y_pred,y_true=y)
print('train_ks : ', train_ks)
y_pred = model.predict_proba(valx)[:,1]
fpr_val,tpr_val,_ = roc_curve(valy, y_pred)
val_ks = abs(fpr_val - tpr_val).max()
val_auc = roc_auc_score(y_score=y_pred,y_true=valy)
print('val_ks : ', val_ks)
plt.plot(fpr_dev, tpr_dev, label='dev:{:.3f}'.format(dev_auc))
plt.plot(fpr_val, tpr_val, label='val:{:.3f}'.format(val_auc))
plt.plot([0,1], [0,1], 'k--')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC Curve')
plt.legend(loc='best')
plt.show()
定義函數(shù)調(diào)用模型
def bi_train():
train_x,train_y = train_set[fea_lst],train_set[target]
valid_x,valid_y = valid_set[fea_lst],valid_set[target]
test_x = test_set[fea_lst]
print("正向邏輯回歸")
lr_model(x=train_x,y=train_y,valx=valid_x,valy=valid_y,C=0.1)
print("反向向邏輯回歸")
lr_model(x= valid_x,y=valid_y,valx=train_x,valy=train_y,C=0.1)
print("XGBoost")
xgb_model(x=train_x,y=train_y,valx=valid_x,valy=valid_y)
bi_train()
從正向和反向邏輯回歸的結(jié)果來(lái)看,模型的性能并沒有很大的差異。在正向模型中,驗(yàn)證集上的AUC為0.836,KS為0.53。模型表現(xiàn)出良好的性能。而在反向模型中,驗(yàn)證集(即正向中的訓(xùn)練集)上的AUC為0.845,KS為0.54。與正向模型相比,KS差異不超過(guò)5%,因此模型足夠穩(wěn)定,不需要調(diào)整數(shù)據(jù)集或過(guò)濾不穩(wěn)定的特征。從XGBoost的性能評(píng)估結(jié)果來(lái)看,其AUC為0.847,與正向模型中0.836相比并沒有顯著的提升。因此,當(dāng)前使用的特征不需要進(jìn)行交叉組合來(lái)提升模型的非線性能力。
4. 模型訓(xùn)練
經(jīng)過(guò)預(yù)訓(xùn)練過(guò)程的分析后,當(dāng)前的數(shù)據(jù)集以及特征基本上不需要進(jìn)行改動(dòng),因此將訓(xùn)練集與驗(yàn)證集合并重新訓(xùn)練模型,作為最終的評(píng)分卡模型。
經(jīng)過(guò)預(yù)訓(xùn)練過(guò)程的分析后,當(dāng)前的數(shù)據(jù)集以及特征基本上不需要進(jìn)行改動(dòng),因此將訓(xùn)練集與驗(yàn)證集合并重新訓(xùn)練模型,作為最終的評(píng)分卡模型。
model = LogisticRegression(C=0.1, class_weight='balanced')
all_train = pd.concat([train_set,valid_set],axis=0)
model.fit(all_train[fea_lst],all_train[target])
#在測(cè)試集上預(yù)測(cè)標(biāo)簽
pro = model.predict_proba(test_set[fea_lst])[:,1]
至此,我們已經(jīng)完成了模型的訓(xùn)練和評(píng)估。由于這里使用的測(cè)試集是沒有標(biāo)簽的,因此無(wú)法評(píng)估最終模型在測(cè)試集上的表現(xiàn)。在實(shí)際建模中,需要重新評(píng)估模型在測(cè)試集上的性能。同樣包括AUC,F(xiàn)1,KS等。此外,也需要評(píng)估模型在訓(xùn)練集和測(cè)試集上的PSI,以驗(yàn)證模型的穩(wěn)定性。
2.4 評(píng)分卡生成
在第一部分的信用評(píng)分卡介紹中我們看到,實(shí)際應(yīng)用的評(píng)分卡應(yīng)當(dāng)是是一張有分?jǐn)?shù)刻度和相應(yīng)閾值的表。邏輯回歸的輸出是一個(gè)概率,即該樣本是壞客戶的概率。因此,我們需要將這種概率進(jìn)行轉(zhuǎn)換,形成一個(gè)分?jǐn)?shù)。這就是評(píng)分卡建模的最后一步,即評(píng)分卡的生成。
對(duì)于評(píng)分卡的生成原理,我們先從感性的角度來(lái)理解。首先,最終的評(píng)分應(yīng)當(dāng)是每個(gè)特征的得分的總和,這樣才能體現(xiàn)出每個(gè)特征的貢獻(xiàn)。另一方面,評(píng)分應(yīng)當(dāng)隨著預(yù)測(cè)風(fēng)險(xiǎn)的增加或降低來(lái)相應(yīng)地降分或加分。并且增加或減少多少分應(yīng)該有一個(gè)固定的映射關(guān)系,這個(gè)映射關(guān)系要與模型初始輸出的概率p有關(guān)。這樣我們才能夠根據(jù)不同評(píng)分的差異來(lái)量化這個(gè)風(fēng)險(xiǎn)變化的大小。那么,邏輯回歸中有哪些地方可以涵蓋這兩個(gè)方面呢?那就是對(duì)數(shù)幾率。在邏輯回歸中有如下關(guān)系。
#woe的編碼規(guī)則
woe_map = woe_t.export()
woe_map
#得到特征,分箱編號(hào)以及分箱woe值的表
woe_df = []
for f in fea_lst:
woes = woe_map.get(f)
for b in woes.keys():
woe_df.append([f,b,woes.get(b)])
woe_df = pd.DataFrame(columns=['feature','bins','woe'],data=woe_df)
woe_df
#生成分箱區(qū)間
bins = combiner.export()
bin_df = []
for fea in fea_lst:
f_cut = bins.get(fea)
f_cut = [float('-inf')] + f_cut + [float('inf')]
for i in range(len(f_cut)-1):
bin_df.append([fea,i,pd.Interval(f_cut[i],f_cut[i+1])])
bin_df = pd.DataFrame(columns=['feature','bins','interval'],data=bin_df)
bin_df
#生成評(píng)分卡
score_df = pd.merge(woe_df,bin_df,on=['feature','bins'])[['feature','interval','woe']]
coef = model.coef_
#每個(gè)特征的分箱數(shù)
bins_num = [len(bins.get(i))+1 for i in fea_lst]
coef = np.repeat(coef,bins_num).
#模型擬合出來(lái)的參數(shù)
score_df['coef'] = coef
'''
設(shè)定Odds為20:1時(shí)基準(zhǔn)分600分,放Odds增加2倍時(shí)分?jǐn)?shù)減50,即PDO=50
'''
factor = round(50 / np.log(2),0)
offset = round(600 + factor * np.log(20),0)
#BasicScore,即評(píng)分公式中的常數(shù)部分
basic_score = round(offset - factor * model.intercept_[0],0)
score_df['score'] = (-factor * score_df['coef']*score_df['woe']).round(0)
card = score_df[['feature','interval','score']]
#將基準(zhǔn)分加上
card = card.append({'feature':'basic_score','interval':np.nan,'score':basic_score},ignore_index=True)
card
至此,我們已經(jīng)成功生成了信用評(píng)分卡,后續(xù)使用時(shí),可以按照評(píng)分卡定義的分?jǐn)?shù)刻度和閾值,根據(jù)客戶的屬性來(lái)得到最終的得分。
2.5 驗(yàn)證評(píng)分卡的有效性
這里可以根據(jù)前面生成的評(píng)分卡寫一個(gè)映射函數(shù),當(dāng)傳入一個(gè)客戶樣本是自動(dòng)計(jì)算出得分,最后來(lái)對(duì)比好壞客戶的得分差異,如果壞客戶的得分小于好客戶的得分那么表明評(píng)分卡是有效的。
#評(píng)分映射函數(shù)
def map_score(customer):
score = []
for i in customer.index:
#一個(gè)特征的計(jì)分區(qū)間
fea_score = card[card['feature']==i]
for _,row in fea_score.iterrows():
#card中的interval列類型是pd.Interval,直接用in來(lái)判斷是否在區(qū)間內(nèi)
if customer.loc[i] in row['interval']:
score.append(row['score'])
break
score = sum(score) + card[card['feature']=='basic_score']['score']
return score.values[0]
#隨機(jī)選擇相同數(shù)量的好客戶和壞客戶
verify_bad = all_train[all_train[target]==1].sample(frac=0.3)
verify_good = all_train[all_train[target]==0].sample(n=len(verify_bad))
bad_scores = []
good_scores = []
#計(jì)算壞客戶的得分
for _, customer in verify_bad.iterrows():
s = map_score(customer.loc[fea_lst])
bad_scores.append(s)
#計(jì)算好客戶的得分
for _, customer in verify_good.iterrows():
s = map_score(customer.loc[fea_lst])
good_scores.append(s)
ver_score_df = pd.DataFrame(columns=['bad','good'],data=np.array([bad_scores,good_scores]).T)
print("好客戶得分均值:{:.2f}\n壞客戶得分均值:{:.2f}".format(ver_score_df['good'].mean(),ver_score_df['bad'].mean()))
_,pv = ttest_ind(ver_score_df['bad'],ver_score_df['good'],equal_var=False)
print("pvalue:",pv)
從結(jié)果中可以看到壞客戶的得分均值小于好客戶得分,且差異具有統(tǒng)計(jì)意義(p值小于0.001)。表明我們生成 的評(píng)分卡是有效的,對(duì)于壞客戶的確會(huì)得到一個(gè)低的評(píng)分。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-694483.html
3. 總結(jié)
本文從信用卡評(píng)分的基礎(chǔ)概念開始,理解信用評(píng)分卡在風(fēng)控中發(fā)揮的作用。第二部分使用公開的信用數(shù)據(jù)集從0到1建立了一個(gè)信用評(píng)分卡。包括數(shù)據(jù)的探索性分析,數(shù)據(jù)預(yù)處理,評(píng)分卡建模,評(píng)分卡生成以及最后的有效性驗(yàn)證。在建模過(guò)程中也交叉地介紹了一些理論概念,這也有助于理解每一個(gè)步驟具體含義。整體上梳理了風(fēng)控中信用評(píng)分卡的建模流程。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-694483.html
到了這里,關(guān)于金融風(fēng)控?cái)?shù)據(jù)分析-信用評(píng)分卡建模(附數(shù)據(jù)集下載地址)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!