基于Python的貸款逾期預(yù)測(cè)與信用評(píng)分卡建立

簡介

項(xiàng)目介紹: 使用 Kaggle 的 GiveMeSomeCredit 數(shù)據(jù)集, 建立邏輯回歸模型與評(píng)分卡, 對(duì)新申請(qǐng)信用貸款的客戶進(jìn)行違約預(yù)測(cè)與信用評(píng)分,降低貸款用戶違約風(fēng)險(xiǎn)。
負(fù)責(zé)內(nèi)容:1. 基于業(yè)務(wù)理解,使用 python 結(jié)合 Matplotlib、 Seaborn 庫對(duì)各變量進(jìn)行統(tǒng)計(jì)分析與可視化,完成數(shù)據(jù)異常、缺失、重復(fù)值清洗。

  1. 使用 python 實(shí)現(xiàn) 10 個(gè)特征變量的卡方分箱并得到對(duì)應(yīng)分箱 WOE 及 VI 值, 根據(jù)特征重要性最終篩選出 5 個(gè)進(jìn)入模型的特征變量。
  2. 使用過采樣 SMOTE 方法處理數(shù)據(jù)不平衡問題,并建立邏輯回歸模型, 使用 AUC 與 KS 值判斷模型精確度, 并預(yù)測(cè)測(cè)試集每條記錄的客戶標(biāo)簽。
  3. 設(shè)置信用評(píng)分計(jì)算邏輯, 對(duì)測(cè)試集每位用戶進(jìn)行信用打分。 拒絕低分用戶貸款申請(qǐng), 有效降低“壞客戶” 風(fēng)險(xiǎn)。

一、業(yè)務(wù)理解

1. 研究背景

銀行或其他金融貸款機(jī)構(gòu)在信貸業(yè)務(wù)中扮演重要角色,它會(huì)對(duì)貸款人或組織的貸款申請(qǐng)進(jìn)行審批。這種審批決策建立在對(duì)貸款人未來財(cái)務(wù)狀況的評(píng)估。信用評(píng)分卡常被運(yùn)用于這種場(chǎng)景,幫助它們做出最好的決策。信用評(píng)分是指根據(jù)貸款客戶的各種歷史信用資料,利用一定的信用評(píng)分模型,得到不同等級(jí)的信用分?jǐn)?shù),根據(jù)客戶的信用分?jǐn)?shù),授信者可以通過分析客戶按時(shí)還款的可能性,據(jù)此決定是否給予授信以及授信的額度和利率。如果申請(qǐng)人的信用評(píng)分大于等于金融放款機(jī)構(gòu)所設(shè)定的界限分?jǐn)?shù),此申請(qǐng)?zhí)幱诳山邮艿娘L(fēng)險(xiǎn)水平并將被批準(zhǔn);低于界限分?jǐn)?shù)的申請(qǐng)人將被拒絕或給予標(biāo)示以便進(jìn)一步審查。

2. 研究目的與框架

本研究目的是建立邏輯回歸模型和信用評(píng)分卡模型,對(duì)測(cè)試集中貸款人未來是否會(huì)逾期進(jìn)行預(yù)測(cè)并打分,幫助金融機(jī)構(gòu)更好的做審批決策??蚣苋缦拢?/p>

  • 業(yè)務(wù)理解,項(xiàng)目背景、研究目的及框架闡述。
  • 數(shù)據(jù)探索性分析,對(duì)樣本進(jìn)行描述性統(tǒng)計(jì),并使用直方圖、箱形圖等描繪單變量分布形態(tài),分析變量間相關(guān)性。
  • 數(shù)據(jù)預(yù)處理,結(jié)合EDA情況進(jìn)行數(shù)據(jù)清洗,包括重復(fù)值、缺失值和異常值處理。
  • 分箱與變量選擇,變量分箱,對(duì)應(yīng)WOE和VI值計(jì)算,并篩選對(duì)違約狀態(tài)影響最顯著的指標(biāo)進(jìn)入模型。
  • 模型建立與評(píng)價(jià),該步驟主要包括變量的WOE(證據(jù)權(quán)重)變換、樣本不均衡處理、邏輯回歸模型構(gòu)建和模型評(píng)估四部分。
  • 測(cè)試集預(yù)測(cè)與信用評(píng)分卡建立,包括預(yù)測(cè)測(cè)試集用戶違約情況并建立信用評(píng)分卡,最終對(duì)測(cè)試集用戶進(jìn)行打分。

二、數(shù)據(jù)探索性分析(EDA)

1. 數(shù)據(jù)來源

數(shù)據(jù)來源于Kaggle的GiveMeSomeCredit比賽,包括數(shù)據(jù)字典、訓(xùn)練集和測(cè)試集。其中訓(xùn)練集有15萬條的樣本數(shù)據(jù),測(cè)試集有10萬余條數(shù)據(jù)。

image.png

為方便后續(xù)處理,這里先將列名統(tǒng)一重命名為中文,并去除序號(hào)列。需要預(yù)測(cè)的是好壞客戶這個(gè)變量,其他變量均為自變量。

column={'Unnamed: 0':'用戶ID',
        'SeriousDlqin2yrs':'好壞客戶',
        'RevolvingUtilizationOfUnsecuredLines':'可用額度比',
        'age':'年齡',
        'NumberOfTime30-59DaysPastDueNotWorse':'逾期30-59天筆數(shù)',
        'DebtRatio':'負(fù)債率',
        'MonthlyIncome':'月收入',
        'NumberOfOpenCreditLinesAndLoans':'信貸數(shù)量',
        'NumberOfTimes90DaysLate':'逾期90天筆數(shù)',
        'NumberRealEstateLoansOrLines':'固定資產(chǎn)貸款數(shù)量',
        'NumberOfTime60-89DaysPastDueNotWorse':'逾期60-89天筆數(shù)',
        'NumberOfDependents':'家屬數(shù)量'}
data.rename(columns=column,inplace=True)
#去除訓(xùn)練集中用戶ID列
data.drop(['用戶ID'],axis=1,inplace=True)
image.png

下表為整理后的數(shù)據(jù)字典描述:

image.png

2. 數(shù)據(jù)描述性統(tǒng)計(jì)

image.png

上圖可知,訓(xùn)練集數(shù)據(jù)有150000行,均為數(shù)值變量,且月收入和家屬數(shù)量變量存在部分缺失。

image.png

其中月收入缺失約19.6%,家屬數(shù)量缺失約2.6%。一般缺失值很少時(shí)可以選擇刪除缺失樣本。另外缺失值也可以選擇填充,包括根據(jù)樣本間相似性填充、變量間相關(guān)關(guān)系填充和虛擬變量填充。最基本的填充法有均值、中位數(shù)、眾數(shù)填充,也可以通過模型擬合等方法。具體填充方法后文數(shù)據(jù)預(yù)處理中詳述。
缺失值處理方法參考 https://segmentfault.com/a/1190000015801384?utm_source=tag-newest

image.png

描述性統(tǒng)計(jì)發(fā)現(xiàn),許多變量存在異常值,決定先對(duì)每個(gè)自變量進(jìn)行單變量分析,觀察其特征分布情況,方便特征工程選用合適方法對(duì)存在的異常值、缺失值進(jìn)行處理。

3. 單變量分析

(1) 好壞客戶
#EDA 客戶類型
plt.figure(figsize=(8,5))
cus_class=data['好壞客戶'].value_counts()
cus_class.plot('bar')
plt.title("好壞客戶分布直方圖")
plt.xlabel("好壞客戶")
plt.ylabel("頻數(shù)")
for x,y in zip(cus_class.index,cus_class):
    plt.text(x, y, '%.0f' % y, ha='center', va= 'bottom',fontsize=10)
image.png

上圖中0為好客戶,1為壞客戶。由直方圖可知,好客戶有139974個(gè),而壞客戶僅10026個(gè),約占6.6%,分布極其不平衡。不平衡數(shù)據(jù)會(huì)造成以總體分類準(zhǔn)確率為學(xué)習(xí)目標(biāo)的傳統(tǒng)分類算法過多地關(guān)注多數(shù)類,使少數(shù)類樣本的分類性能下降。故建立邏輯回歸模型前需要進(jìn)行過采樣或欠采樣處理。

(2) 年齡
plt.figure(figsize=(8,5))
data_test_0=data.loc[data.好壞客戶 == 0]['年齡']
data_test_1=data.loc[data.好壞客戶 == 1]['年齡']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
image.png

上圖可以看出,年齡基本符合正態(tài)分布,且整體年齡小相較年齡大違約風(fēng)險(xiǎn)更大。為進(jìn)一步分析各年齡段的違約情況,接下來將年齡進(jìn)行分箱并計(jì)算違約率。

age=data.loc[data['年齡']>0,['年齡','好壞客戶']]
age.loc[(data['年齡']<20),'年齡'] = '0-20'
age.loc[(data['年齡']>=20)&(data['年齡']<40),'年齡'] = '20-40'
age.loc[(data['年齡']>=40)&(data['年齡']<60),'年齡'] = '40-60' 
age.loc[(data['年齡']>=60)&(data['年齡']<80),'年齡'] = '60-80'
age.loc[(data['年齡']>=80),'年齡'] = '80+'
age_bad=age.groupby('年齡')['好壞客戶'].sum()
age_total=age.groupby('年齡')['好壞客戶'].count()
age_ratio=age_bad/age_total
age_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖可知,0-20歲缺少數(shù)據(jù),整體分析結(jié)果基本與前面一致,客戶層年齡越大,違約率越低。違約率最大的年齡組為20-40歲,最小的年齡組為80+歲。

(3) 月收入
a=data['月收入'].mean()+3*data['月收入'].std()
b=data['月收入'].mean()-3*data['月收入'].std()
plt.figure(figsize=(8,5))
data_test_0=data.loc[(data['月收入']<=a) & (data['月收入']>=b)][data.好壞客戶 == 0]['月收入']
data_test_1=data.loc[(data['月收入']<=a) & (data['月收入']>=b)][data.好壞客戶 == 1]['月收入']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
image.png

由于月收入被極值影響嚴(yán)重,故先排除3倍標(biāo)準(zhǔn)差的極值再畫圖。如圖,月收入基本符合正態(tài)分布,滿足統(tǒng)計(jì)分析前提。月收入主要集中在0-20000以內(nèi),但是也有少數(shù)極高收入的借款人。另外可以發(fā)現(xiàn),月收入低相較月收入高的客戶,違約風(fēng)險(xiǎn)更大。為進(jìn)一步分析各收入段的違約情況,接下來將月收入進(jìn)行分箱并計(jì)算違約率。

income=data.loc[data['月收入']>0,['月收入','好壞客戶']]
income.loc[(data['月收入']<500),'月收入'] = '1'
income.loc[(data['月收入']>=500)&(data['月收入']<1000),'月收入'] = '2'
income.loc[(data['月收入']>=1000)&(data['月收入']<5000),'月收入'] = '3' 
income.loc[(data['月收入']>=5000)&(data['月收入']<10000),'月收入'] = '4'
income.loc[(data['月收入']>=10000)&(data['月收入']<20000),'月收入'] = '5'
income.loc[(data['月收入']>=20000),'月收入'] = '6'
income_bad=income.groupby('月收入')['好壞客戶'].sum()
income_total=income.groupby('月收入')['好壞客戶'].count()
income_ratio=income_bad/income_total
income_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖顯示月收入在1000-5000的人群違約率最高,接著是收入在500-1000和5000-10000群體,違約比例均超出0.06。

(4) 可用額度比

對(duì)可用額度比整體進(jìn)行畫圖,發(fā)現(xiàn)該變量極差很大,最大值達(dá)到50000以上。從業(yè)務(wù)邏輯出發(fā),可用額度比值應(yīng)該處于0-1之間,但根據(jù)散點(diǎn)圖發(fā)現(xiàn)也有許多大于1的數(shù)字,異常值較多,猜測(cè)部分極大值可能是沒有除以可用額度的值,是純可貸款金額。由于這些異常值可能會(huì)影響分析,接下來分為<=1 和 >1 兩個(gè)部分畫圖分析。

plt.figure(figsize=(8,5))
data_test_0=data.loc[data['可用額度比']<=1][data.好壞客戶 == 0]['可用額度比']
data_test_1=data.loc[data['可用額度比']<=1][data.好壞客戶 == 1]['可用額度比']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
image.png
plt.figure(figsize=(8,5))
data_test_0=data.loc[data['可用額度比']>1][data.好壞客戶 == 0]['可用額度比']
data_test_1=data.loc[data['可用額度比']>1][data.好壞客戶 == 1]['可用額度比']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
image.png

可以發(fā)現(xiàn)在可用額度比小于等于1的情況下,當(dāng)可用額度比小于0.4時(shí),違約概率較小;當(dāng)其大于0.4時(shí),可用額度比越大,違約概率越高;而當(dāng)可用額度比大于1時(shí),由于數(shù)值分布過于分散,看不出明顯規(guī)律。下面將可用額度比再進(jìn)行細(xì)化分箱。

bins=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
data['可用額度分箱']=pd.cut(data['可用額度比'],bins,right=True)
#違約率
revol_bad=data.groupby(['可用額度分箱'])['好壞客戶'].sum()
revol_total=data.groupby(['可用額度分箱'])['好壞客戶'].count()
revol_ratio=revol_bad/revol_total
revol_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖可看出可用額度比<=1時(shí),違約率與可用額度比正相關(guān)。可用額度比越高違約率越大。

bins=[1,10,100,1000,10000,60000]
data['可用額度分箱']=pd.cut(data['可用額度比'],bins,right=True)
#違約率
revol_bad=data.groupby(['可用額度分箱'])['好壞客戶'].sum()
revol_total=data.groupby(['可用額度分箱'])['好壞客戶'].count()
revol_ratio=revol_bad/revol_total
revol_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖可看出可用額度比>1時(shí),1-10和10-100兩個(gè)區(qū)間的違約均大于0.3,大于可用額度比小于1的違約率??捎妙~度比[0,10]區(qū)間基本符合上述可用額度比越大,違約風(fēng)險(xiǎn)越大的分析。

a=data.loc[(data['可用額度比']>1) & (data['可用額度比']<=10)]['可用額度比'].count() 
b=data.loc[(data['可用額度比']>1) & (data['可用額度比']<=70000)]['可用額度比'].count()
a/b

計(jì)算發(fā)現(xiàn)可用額度比大于1小于等于10的變量約占所有大于1數(shù)據(jù)的93%,過大的值可能是不具有代表性的異常值。

(5) 負(fù)債率

從業(yè)務(wù)邏輯出發(fā),負(fù)債率應(yīng)該處于0-1之間,但根據(jù)散點(diǎn)圖發(fā)現(xiàn)也有許多大于1的數(shù)字,異常值較多。由于這些異常值可能會(huì)影響分析,接下來分為<=1 和 >1 兩個(gè)部分畫圖分析。

plt.figure(figsize=(8,5))
data_test_0=data.loc[data['負(fù)債率']<=1][data.好壞客戶 == 0]['負(fù)債率']
data_test_1=data.loc[data['負(fù)債率']<=1][data.好壞客戶 == 1]['負(fù)債率']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
plt.show()
sns.boxplot(y=data['負(fù)債率'])
image.png
image.png

當(dāng)負(fù)債率小于等于1的時(shí)候,好客戶更多集中于0-0.4之間,而壞客戶分布較為平均且擁有長尾屬性,負(fù)債率大于0.45后,違約風(fēng)險(xiǎn)較大。

plt.figure(figsize=(8,5))
data_test_0=data.loc[data['負(fù)債率']>1][data.好壞客戶 == 0]['負(fù)債率']
data_test_1=data.loc[data['負(fù)債率']>1][data.好壞客戶 == 1]['負(fù)債率']
sns.distplot(data_test_0.dropna(),color='g')
sns.distplot(data_test_1.dropna(),color='r')
plt.legend(['0','1'])
image.png

當(dāng)負(fù)債率大于1的時(shí)候,出現(xiàn)壞客戶的概率遠(yuǎn)大于好客戶。另外,負(fù)債率存在極大值。

bins=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
data['負(fù)債率分箱']=pd.cut(data['負(fù)債率'],bins,right=True)
#違約率
debt_bad=data.groupby(['負(fù)債率分箱'])['好壞客戶'].sum()
debt_total=data.groupby(['負(fù)債率分箱'])['好壞客戶'].count()
debt_ratio=debt_bad/debt_total
debt_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖可看出負(fù)債率<=1時(shí),負(fù)債率與違約率正相關(guān)趨勢(shì)。負(fù)債率越高違約率越大。

bins=[1,5000,10000,20000,40000]
data['負(fù)債率分箱']=pd.cut(data['負(fù)債率'],bins,right=True)
#違約率
debt_bad=data.groupby(['負(fù)債率分箱'])['好壞客戶'].sum()
debt_total=data.groupby(['負(fù)債率分箱'])['好壞客戶'].count()
debt_ratio=debt_bad/debt_total
debt_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖可看出負(fù)債率>1時(shí),基本符合負(fù)債率和違約率正相關(guān)的分析。

(6) 逾期筆數(shù)(逾期30-59天筆數(shù)、逾期60-89天筆數(shù)、逾期90天筆數(shù))
#逾期筆數(shù)
list=['逾期30-59天筆數(shù)','逾期60-89天筆數(shù)','逾期90天筆數(shù)']
#a=[ax1,ax2,ax3]
b=0
fig,a=plt.subplots(2,3,figsize=(15,8))
for i in list:
    pvt=pd.pivot_table(data[['好壞客戶',i]], index=i, columns='好壞客戶', aggfunc=len)
    pvt.plot(kind='bar',ax=a[0,b])
    sns.boxplot(y=data[i],ax=a[1,b])
    b=b+1
image.png

由箱線圖可以看出,三個(gè)逾期筆數(shù)均存在異常值,使用value_counts函數(shù)得知為96和98兩個(gè)異常值,后續(xù)應(yīng)剔除。

#將大于40的數(shù)據(jù)和40合并后看一下違約率的情況
Num_bad=data.groupby(['逾期30-59天筆數(shù)'])['好壞客戶'].sum()
Num_total=data.groupby(['逾期30-59天筆數(shù)'])['好壞客戶'].count()
Num_ratio=Num_bad/Num_total
Num_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png
Num_bad=data.groupby(['逾期60-89天筆數(shù)'])['好壞客戶'].sum()
Num_total=data.groupby(['逾期60-89天筆數(shù)'])['好壞客戶'].count()
Num_ratio=Num_bad/Num_total
Num_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png
Num_bad=data.groupby(['逾期90天筆數(shù)'])['好壞客戶'].sum()
Num_total=data.groupby(['逾期90天筆數(shù)'])['好壞客戶'].count()
Num_ratio=Num_bad/Num_total
Num_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

部分區(qū)間逾期筆數(shù)與違約率有正相關(guān)關(guān)系。

(7) 信貸數(shù)量、固定資產(chǎn)貸款數(shù)量
#資貸數(shù)量
list=['信貸數(shù)量','固定資產(chǎn)貸款數(shù)量']
b=0
fig,a=plt.subplots(2,2,figsize=(15,8))
for i in list:
    pvt=pd.pivot_table(data[['好壞客戶',i]], index=i, columns='好壞客戶', aggfunc=len)
    pvt.plot(kind='bar',ax=a[0,b])
    sns.boxplot(y=data[i],ax=a[1,b])
    b=b+1
image.png

將信貸數(shù)量大于40的數(shù)據(jù)和40合并后看一下違約率的情況。

data.loc[data['信貸數(shù)量']>40,'信貸數(shù)量']=40
Num_bad=data.groupby(['信貸數(shù)量'])['好壞客戶'].sum()
Num_total=data.groupby(['信貸數(shù)量'])['好壞客戶'].count()
Num_ratio=Num_bad/Num_total
Num_ratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

信貸數(shù)量與違約率無明顯相關(guān)性。下面將固定資產(chǎn)貸款數(shù)量大于8的數(shù)據(jù)和8合并后看一下違約率的情況。

data.loc[data['固定資產(chǎn)貸款數(shù)量']>8,'固定資產(chǎn)貸款數(shù)量']=8
Num_bad=data.groupby(['固定資產(chǎn)貸款數(shù)量'])['好壞客戶'].sum()
Num_total=data.groupby(['固定資產(chǎn)貸款數(shù)量'])['好壞客戶'].count()
Num_ratio=Num_bad/Num_total
Num_ratio.plot(kind='bar',figsize=(8,6),color='#4682B4')
image.png

由圖可知,固定資產(chǎn)貸款數(shù)量從1開始,違約率隨著固定資產(chǎn)貸款數(shù)量增大而增大。

(8) 家屬數(shù)量
plt.figure(figsize=(8,5))
cus_class=data['家屬數(shù)量'].value_counts()
cus_class.plot('bar',color='#4682B4')
plt.title("家屬數(shù)量分布直方圖")
plt.xlabel("家屬數(shù)量")
plt.ylabel("頻數(shù)")
for x,y in zip(cus_class.index,cus_class):
    plt.text(x, y, '%.0f' % y, ha='center', va= 'bottom',fontsize=10)
plt.show()
plt.figure(figsize=(8,5))
sns.boxplot(y=data['家屬數(shù)量'])
image.png
image.png

將大于8的數(shù)據(jù)和8合并后看一下家屬數(shù)量的情況。

Numestate_dlq=data.groupby(['家屬數(shù)量'])['好壞客戶'].sum()
Numestate_total=data.groupby(['家屬數(shù)量'])['好壞客戶'].count()
Numestate_dlqratio=Numestate_dlq/Numestate_total
Numestate_dlqratio.plot(kind='bar',figsize=(8,5),color='#4682B4')
image.png

上圖所示,家屬數(shù)量為6時(shí)違約率最高,超過14%。但家屬數(shù)量與違約率并無顯著相關(guān)性。

三、數(shù)據(jù)預(yù)處理

1. 重復(fù)值處理

#去除訓(xùn)練集中的完全重復(fù)行
data.drop_duplicates(keep='first',inplace=True)
print("預(yù)處理后訓(xùn)練集大小 : {} ".format(data.shape))

由于訓(xùn)練集數(shù)據(jù)量較大,難免存在重復(fù)數(shù)據(jù),為保證數(shù)據(jù)質(zhì)量,需要將訓(xùn)練集中完全重復(fù)的行數(shù)據(jù)去除。

image.png

通過上述預(yù)處理后,訓(xùn)練集長度變?yōu)?49391條,列數(shù)變?yōu)?1列。

2. 缺失值處理

image.png

在前文描述性統(tǒng)計(jì)部分中,我們發(fā)現(xiàn)月收入缺失約19.6%,家屬數(shù)量缺失約2.6%。

data['家屬數(shù)量'].fillna(data['家屬數(shù)量'].median(),inplace=True) # 填充中位數(shù)

由于“家屬數(shù)量”缺失比例較少,這里選擇直接用中位數(shù)進(jìn)行填充。而月收入變量缺失較多,且根據(jù)業(yè)務(wù)邏輯推測(cè)此變量對(duì)因變量影響較大,這里選用隨機(jī)森林填補(bǔ)法來填充,即將缺失的特征值作為預(yù)測(cè)值,將未缺失的“月收入”數(shù)據(jù)作為訓(xùn)練樣本的標(biāo)簽。

#隨機(jī)森林預(yù)測(cè)缺失值
data_Forest=data.iloc[:,[5,0,1,2,3,4,6,7,8,9,10]]
MonthlyIncome_isnull=data_Forest.loc[data['月收入'].isnull(),:]
MonthlyIncome_notnull=data_Forest.loc[data['月收入'].notnull(),:]
from sklearn.ensemble import RandomForestRegressor
X=MonthlyIncome_notnull.iloc[:,1:].values
y=MonthlyIncome_notnull.iloc[:,0].values
regr=RandomForestRegressor(random_state=0,n_estimators=200,n_jobs=-1)
regr.fit(X,y)
MonthlyIncome_fillvalue=regr.predict(MonthlyIncome_isnull.iloc[:,1:].values).round(0)
#填充缺失值
data.loc[data['月收入'].isnull(),'月收入']=MonthlyIncome_fillvalue

3. 異常值處理

由value_counts函數(shù)可知,年齡變量存在等于0的異常值,這里進(jìn)行刪除。另外,通過箱線圖,發(fā)現(xiàn)逾期30-59天筆數(shù)、逾期60-80天筆數(shù)、逾期90天筆數(shù),這三個(gè)變量均存在嚴(yán)重的離群值,應(yīng)進(jìn)行異常值處理。

data=data[data['年齡']>0]
data=data[data['逾期30-59天筆數(shù)']<80]
data=data[data['逾期60-89天筆數(shù)']<80]
data=data[data['逾期90天筆數(shù)']<80]

4. 變量相關(guān)性分析

由于變量間共線性問題在部分機(jī)器學(xué)習(xí)模型中會(huì)顯著影響模型性能,需針對(duì)選擇的模型進(jìn)行特殊處理,故這里進(jìn)行相關(guān)性分析檢驗(yàn)。

fig = plt.figure(figsize = (8,5))
sns.heatmap(data.iloc[:,:11].corr(),annot=True, cmap='YlGnBu', annot_kws={'size': 9})
image.png

上圖為各自變量的相關(guān)系數(shù)矩陣,顏色越深表明兩變量相關(guān)性越高。由圖可知,除對(duì)角線區(qū)域,大多數(shù)區(qū)域顏色較淺,未有變量相關(guān)性超過0.5,基本不存在變量間共線性問題。

四、分箱與變量選擇

1. 特征變量標(biāo)準(zhǔn)化

本文計(jì)劃使用邏輯回歸模型,其中數(shù)值型變量數(shù)據(jù)需要進(jìn)行歸一化處理使數(shù)值在同一個(gè)數(shù)量級(jí)上,保證邏輯回歸的收斂速度。但由于后文會(huì)使用WOE轉(zhuǎn)換,故這里不另外進(jìn)行標(biāo)準(zhǔn)化處理。

2. 特征離散化(分箱)

由于本文選擇用邏輯回歸建立評(píng)分卡模型,連續(xù)變量需要進(jìn)行離散化,該處理會(huì)使模型更穩(wěn)定,降低過擬合的風(fēng)險(xiǎn)。首先將連續(xù)變量進(jìn)行離散化分箱處理,通過比較指標(biāo)分箱后的WOE與VI值進(jìn)一步確定指標(biāo)對(duì)因變量的貢獻(xiàn)度,選取貢獻(xiàn)高的變量引入后續(xù)模型。

常用的分箱方法包括無監(jiān)督分箱(等距分箱、等頻分箱和聚類分箱)和有監(jiān)督分箱(卡方分箱和best-ks分箱)。下文將采用卡方分箱法??ǚ椒窒涫且蕾囉诳ǚ綑z驗(yàn)的分箱方法,在統(tǒng)計(jì)指標(biāo)上選擇卡方統(tǒng)計(jì)量(chi-Square)進(jìn)行判別,分箱的基本思想是判斷相鄰的兩個(gè)區(qū)間是否有分布差異,基于卡方統(tǒng)計(jì)量的結(jié)果進(jìn)行自下而上的合并,直到滿足分箱的限制條件為止。

temp = data[['年齡','好壞客戶']]
# 定義一個(gè)卡方分箱(可設(shè)置參數(shù)置信度水平與箱的個(gè)數(shù))停止條件為大于置信水平且小于bin的數(shù)目
def ChiMerge(df, variable, flag, confidenceVal=3.841, bin=10, sample = None):  
    '''
    運(yùn)行前需要 import pandas as pd 和 import numpy as np
    df:傳入一個(gè)數(shù)據(jù)框僅包含一個(gè)需要卡方分箱的變量與正負(fù)樣本標(biāo)識(shí)(正樣本為1,負(fù)樣本為0)
    variable:需要卡方分箱的變量名稱(字符串)
    flag:正負(fù)樣本標(biāo)識(shí)的名稱(字符串)
    confidenceVal:置信度水平(默認(rèn)是不進(jìn)行抽樣95%)
    bin:最多箱的數(shù)目
    sample: 為抽樣的數(shù)目(默認(rèn)是不進(jìn)行抽樣),因?yàn)槿绻^測(cè)值過多運(yùn)行會(huì)較慢
    '''
#進(jìn)行是否抽樣操作
    if sample != None:
        df = df.sample(n=sample)
    else:
        df   

#進(jìn)行數(shù)據(jù)格式化錄入
    total_num = df.groupby([variable])[flag].count()  # 統(tǒng)計(jì)需分箱變量每個(gè)值數(shù)目
    total_num = pd.DataFrame({'total_num': total_num})  # 創(chuàng)建一個(gè)數(shù)據(jù)框保存之前的結(jié)果
    positive_class = df.groupby([variable])[flag].sum()  # 統(tǒng)計(jì)需分箱變量每個(gè)值正樣本數(shù)
    positive_class = pd.DataFrame({'positive_class': positive_class})  # 創(chuàng)建一個(gè)數(shù)據(jù)框保存之前的結(jié)果
    regroup = pd.merge(total_num, positive_class, left_index=True, right_index=True,
                       how='inner')  # 組合total_num與positive_class
    regroup.reset_index(inplace=True)
    regroup['negative_class'] = regroup['total_num'] - regroup['positive_class']  # 統(tǒng)計(jì)需分箱變量每個(gè)值負(fù)樣本數(shù)
    regroup = regroup.drop('total_num', axis=1)
    np_regroup = np.array(regroup)  # 把數(shù)據(jù)框轉(zhuǎn)化為numpy(提高運(yùn)行效率),每行為年齡,壞客戶數(shù),好客戶數(shù)
    print('已完成數(shù)據(jù)讀入,正在計(jì)算數(shù)據(jù)初處理')

#處理連續(xù)沒有正樣本或負(fù)樣本的區(qū)間,并進(jìn)行區(qū)間的合并(以免卡方值計(jì)算報(bào)錯(cuò))
    i = 0
    while (i <= np_regroup.shape[0] - 2):  #np_regroup.shape[0]行數(shù)
        if ((np_regroup[i, 1] == 0 and np_regroup[i + 1, 1] == 0) or ( np_regroup[i, 2] == 0 and np_regroup[i + 1, 2] == 0)):
            np_regroup[i, 1] = np_regroup[i, 1] + np_regroup[i + 1, 1]  # 正樣本
            np_regroup[i, 2] = np_regroup[i, 2] + np_regroup[i + 1, 2]  # 負(fù)樣本
            np_regroup[i, 0] = np_regroup[i + 1, 0]
            np_regroup = np.delete(np_regroup, i + 1, 0)
            i = i - 1
        i = i + 1
 
#對(duì)相鄰兩個(gè)區(qū)間進(jìn)行卡方值計(jì)算
    chi_table = np.array([])  # 創(chuàng)建一個(gè)數(shù)組保存相鄰兩個(gè)區(qū)間的卡方值
    for i in np.arange(np_regroup.shape[0] - 1):
        chi = (np_regroup[i, 1] * np_regroup[i + 1, 2] - np_regroup[i, 2] * np_regroup[i + 1, 1]) ** 2 \
          * (np_regroup[i, 1] + np_regroup[i, 2] + np_regroup[i + 1, 1] + np_regroup[i + 1, 2]) / \
          ((np_regroup[i, 1] + np_regroup[i, 2]) * (np_regroup[i + 1, 1] + np_regroup[i + 1, 2]) * (
          np_regroup[i, 1] + np_regroup[i + 1, 1]) * (np_regroup[i, 2] + np_regroup[i + 1, 2]))
        chi_table = np.append(chi_table, chi)
    print('已完成數(shù)據(jù)初處理,正在進(jìn)行卡方分箱核心操作')

#把卡方值最小的兩個(gè)區(qū)間進(jìn)行合并(卡方分箱核心)
    while (1):
        if (len(chi_table) <= (bin - 1) and min(chi_table) >= confidenceVal):
            break
        chi_min_index = np.argwhere(chi_table == min(chi_table))[0]  # 找出卡方值最小的位置索引
        np_regroup[chi_min_index, 1] = np_regroup[chi_min_index, 1] + np_regroup[chi_min_index + 1, 1]
        np_regroup[chi_min_index, 2] = np_regroup[chi_min_index, 2] + np_regroup[chi_min_index + 1, 2]
        np_regroup[chi_min_index, 0] = np_regroup[chi_min_index + 1, 0]
        np_regroup = np.delete(np_regroup, chi_min_index + 1, 0)

        if (chi_min_index == np_regroup.shape[0] - 1):  # 最小值試最后兩個(gè)區(qū)間的時(shí)候
            # 計(jì)算合并后當(dāng)前區(qū)間與前一個(gè)區(qū)間的卡方值并替換
            chi_table[chi_min_index - 1] = (np_regroup[chi_min_index - 1, 1] * np_regroup[chi_min_index, 2] - np_regroup[chi_min_index - 1, 2] * np_regroup[chi_min_index, 1]) ** 2 \
                                           * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) / \
                                       ((np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2]) * (np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index, 1]) * (np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 2]))
            # 刪除替換前的卡方值
            chi_table = np.delete(chi_table, chi_min_index, axis=0)

        else:
            # 計(jì)算合并后當(dāng)前區(qū)間與前一個(gè)區(qū)間的卡方值并替換
            chi_table[chi_min_index - 1] = (np_regroup[chi_min_index - 1, 1] * np_regroup[chi_min_index, 2] - np_regroup[chi_min_index - 1, 2] * np_regroup[chi_min_index, 1]) ** 2 \
                                       * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) / \
                                       ((np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2]) * (np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index, 1]) * (np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 2]))
            # 計(jì)算合并后當(dāng)前區(qū)間與后一個(gè)區(qū)間的卡方值并替換
            chi_table[chi_min_index] = (np_regroup[chi_min_index, 1] * np_regroup[chi_min_index + 1, 2] - np_regroup[chi_min_index, 2] * np_regroup[chi_min_index + 1, 1]) ** 2 \
                                       * (np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2] + np_regroup[chi_min_index + 1, 1] + np_regroup[chi_min_index + 1, 2]) / \
                                   ((np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (np_regroup[chi_min_index + 1, 1] + np_regroup[chi_min_index + 1, 2]) * (np_regroup[chi_min_index, 1] + np_regroup[chi_min_index + 1, 1]) * (np_regroup[chi_min_index, 2] + np_regroup[chi_min_index + 1, 2]))
            # 刪除替換前的卡方值
            chi_table = np.delete(chi_table, chi_min_index + 1, axis=0)
    print('已完成卡方分箱核心操作,正在保存結(jié)果')

#把結(jié)果保存成一個(gè)數(shù)據(jù)框
    result_data = pd.DataFrame()  # 創(chuàng)建一個(gè)保存結(jié)果的數(shù)據(jù)框
    result_data['variable'] = [variable] * np_regroup.shape[0]  # 結(jié)果表第一列:變量名
    list_temp = []
    for i in np.arange(np_regroup.shape[0]):
        if i == 0:
            x = '0' + ',' + str(np_regroup[i, 0])
        elif i == np_regroup.shape[0] - 1:
            x = str(np_regroup[i - 1, 0]) + '+'
        else:
            x = str(np_regroup[i - 1, 0]) + ',' + str(np_regroup[i, 0])
        list_temp.append(x)
    result_data['interval'] = list_temp  # 結(jié)果表第二列:區(qū)間
    result_data['good_count'] = np_regroup[:, 2]  # 結(jié)果表第三列:負(fù)樣本數(shù)目
    result_data['bad_count'] = np_regroup[:, 1]  # 結(jié)果表第四列:正樣本數(shù)目
    bad_total=result_data['bad_count'].sum()
    good_total=result_data['good_count'].sum()
    result_data['woe']=np.log((result_data['bad_count']/bad_total)/(result_data['good_count']/good_total))  # 結(jié)果表第五列:WOE值
    result_data['VI']=((result_data['bad_count']/bad_total)-(result_data['good_count']/good_total))*result_data['woe']
    return result_data

#調(diào)用參數(shù)并保存結(jié)果到集合
bins = ChiMerge(temp, '年齡','好壞客戶', confidenceVal=3.841, bin=10,sample=None)
print(bins)
vi=bins['VI'].sum()
print('%s特征的VI值為%.4f' %(temp.columns[0],vi))
vi_total={}
vi_total[temp.columns[0]] = vi

以年齡特征為例,分箱結(jié)果如下:

image.png

接著對(duì)其余連續(xù)性變量同樣進(jìn)行卡方分箱,由于特征較多而處理方式一致,這里省略其他特征的具體分箱結(jié)果。

3. WOE和IV值計(jì)算與分析

由于邏輯回歸模型需要數(shù)值作為變量輸入,接下來需要計(jì)算分箱對(duì)應(yīng)WOE值。WOE越大,代表這個(gè)變量對(duì)“壞客戶“標(biāo)簽的貢獻(xiàn)度越大。

IV(Information Value)是與WOE密切相關(guān)的一個(gè)指標(biāo),常用來評(píng)估變量的預(yù)測(cè)能力,可以結(jié)合其結(jié)果篩選變量。在應(yīng)用實(shí)踐中,其評(píng)價(jià)標(biāo)準(zhǔn)如下:

image.png

這里依舊以年齡變量為例,年齡特征的VI值為0.2589。接著對(duì)其余連續(xù)性變量同樣進(jìn)行卡方分箱,并得到對(duì)應(yīng)WOE和IV值。由于特征較多而處理方式一致,這里省略其他特征的具體結(jié)果。

4. 特征變量選擇

最終我們將VI值進(jìn)行整理,得到各特征VI值條形圖。

def draw_from_dict(dicdata,RANGE):
    by_value = sorted(dicdata.items(),key = lambda item:item[1],reverse=True)
    print(by_value)
    x = []
    y = []
    for d in by_value:
        x.append(d[0])
        y.append(d[1])
    plt.yticks(np.arange(len(x)),x)
    plt.barh(np.arange(len(x)), y[0:RANGE])
    plt.show()
    return 
a=draw_from_dict(vi_total,len(vi_total))
image.png

根據(jù)VI預(yù)測(cè)效果表,選取VI>0.1的變量進(jìn)入邏輯回歸模型,包括可用額度比、逾期60-89天筆數(shù)、逾期30-59天筆數(shù)、逾期90天筆數(shù)和年齡。

五、 模型建立與評(píng)價(jià)

1. WOE特征變換

邏輯回歸模型基于廣義線性回歸模型,求參需要用到梯度下降法,為了加快迭代速度,不同特征的變化范圍規(guī)模相差不宜過大,如果用數(shù)值直接帶入邏輯回歸模型,必須進(jìn)行變量縮放。本文對(duì)變量進(jìn)行WOE處理會(huì)將數(shù)值變量進(jìn)行分箱,可以達(dá)到相似效果。將分箱后求得的WOE值替換對(duì)應(yīng)數(shù)值,方便后續(xù)建立邏輯回歸與評(píng)分模型。

image.png

image.png

2. 樣本均衡處理

image.png

原訓(xùn)練集正樣本占比93.38%,負(fù)樣本6.62%,樣本嚴(yán)重不平衡。這里使用SMOTE方法進(jìn)行過采樣處理,處理后樣本共278582條,正負(fù)各占50%。

3. 模型構(gòu)建

本文使用邏輯回歸模型

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
train_x,test_x,train_y,test_y = train_test_split(x,y,test_size = 0.3,random_state = 0)
train = pd.concat([train_y,train_x], axis =1)
test = pd.concat([test_y,test_x], axis =1)
train = train.reset_index(drop=True)
test = test.reset_index(drop=True)
lr = LogisticRegression(penalty= 'l1',solver='liblinear')
lr.fit(train_x,train_y)

4. 模型評(píng)估(ROC、AUC與KS評(píng)估)

AUC是一個(gè)衡量評(píng)分卡區(qū)分能力的量化指標(biāo),AUC面積越大,表示模型區(qū)分能力越強(qiáng),在衡量一個(gè)模型是否有效的時(shí)候,AUC至少需要大于0.5。KS值是一個(gè)衡量好壞客戶分?jǐn)?shù)距離的上限值,具體做法為將對(duì)于各個(gè)分?jǐn)?shù)區(qū)間對(duì)應(yīng)的好壞客戶累計(jì)占比進(jìn)行相減,取最大值。好壞客戶之間的距離越大,k-s指標(biāo)越高,模型的區(qū)分能力越強(qiáng)。

#繪制roc曲線
from sklearn.metrics import roc_curve, auc
y_pred= lr.predict(train_x)  
train_predprob = lr.predict_proba(train_x)[:,1]  
test_predprob = lr.predict_proba(test_x)[:,1] 
FPR,TPR,threshold =roc_curve(test_y,test_predprob)
ROC_AUC= auc(FPR,TPR)
plt.plot(FPR, TPR, 'b', label='AUC = %0.2f' % ROC_AUC)
plt.legend(loc='lower right')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1])
plt.ylim([0, 1])
plt.ylabel('TPR')
plt.xlabel('FPR')
plt.show()
ks=max(TPR-FPR).round(2)
print("auc:{}       ks:{}".format(ROC_AUC.round(2),ks))
image.png

AUC值約為0.84,說明該模型的擬合效果較好。KS值約為0.52,一般KS>0.3即可認(rèn)為模型有比較好的預(yù)測(cè)準(zhǔn)確性。總體來說模型效果不錯(cuò)。

六、測(cè)試集預(yù)測(cè)與信用評(píng)分卡建立

1. 導(dǎo)入測(cè)試集及數(shù)據(jù)預(yù)處理

f=open('F:\GiveMeSomeCredit\cs-test.csv')
data2=pd.read_csv(f)
column={'Unnamed: 0':'用戶ID',
        'SeriousDlqin2yrs':'好壞客戶',
        'RevolvingUtilizationOfUnsecuredLines':'可用額度比',
        'age':'年齡',
        'NumberOfTime30-59DaysPastDueNotWorse':'逾期30-59天筆數(shù)',
        'DebtRatio':'負(fù)債率',
        'MonthlyIncome':'月收入',
        'NumberOfOpenCreditLinesAndLoans':'信貸數(shù)量',
        'NumberOfTimes90DaysLate':'逾期90天筆數(shù)',
        'NumberRealEstateLoansOrLines':'固定資產(chǎn)貸款數(shù)量',
        'NumberOfTime60-89DaysPastDueNotWorse':'逾期60-89天筆數(shù)',
        'NumberOfDependents':'家屬數(shù)量'}
data2.rename(columns=column,inplace=True)
#去除訓(xùn)練集中用戶ID列
data2.drop(['用戶ID'],axis=1,inplace=True)

將測(cè)試集導(dǎo)入,并進(jìn)行與前文訓(xùn)練集一樣的數(shù)據(jù)預(yù)處理,包括缺失值填補(bǔ),異常值刪除,重復(fù)值刪除等。

2. 分箱及WOE轉(zhuǎn)換

image.png
image.png

3. 好壞客戶預(yù)測(cè)

基于前文建立的模型給出測(cè)試集預(yù)測(cè)結(jié)果。

final_test_predict=data_test.reset_index().drop('index',axis=1).copy()
final_test_predict=final_test_predict.iloc[:,[1,2,3,4,5]]
y_pred= lr.predict(final_test_predict)
final_test_predict['好壞客戶']=pd.DataFrame(y_pred)
final_test_predict
image.png

4. 評(píng)分卡建立

在建立標(biāo)準(zhǔn)評(píng)分卡之前,需要選取幾個(gè)評(píng)分卡參數(shù):基礎(chǔ)分值、 PDO(Point-to-Double Odds,好壞比每升高一倍,分?jǐn)?shù)升高PDO個(gè)單位)和好壞比。 這里取600分為基礎(chǔ)分值,PDO為20 (每高20分好壞比翻一倍),好壞比取20。

# 個(gè)人總分=基礎(chǔ)分+各部分得分
import math
B = 20 / math.log(2)
A = 600 - B / math.log(20)
# 基礎(chǔ)分
base = round(A+B *lr.intercept_[0], 0)
base

下面計(jì)算各變量部分的分?jǐn)?shù)。各部分得分函數(shù):

#計(jì)算分?jǐn)?shù)函數(shù)
def compute_score(coe,woe,factor):
    scores=[]
    for w in woe:
        score=round(-coe*w*factor,0)
        scores.append(score)
    return scores

x1_revol = compute_score(lr.coef_[0][0], woe_revol, B)
x2_age = compute_score(lr.coef_[0][1], woe_age, B)
x3_30 = compute_score(lr.coef_[0][2], woe_30, B)
x4_90 = compute_score(lr.coef_[0][3], woe_60, B)
x5_60 = compute_score(lr.coef_[0][4], woe_90, B)

得到每個(gè)變量不同區(qū)間的對(duì)應(yīng)分?jǐn)?shù)。

image.png

得到訓(xùn)練集每個(gè)用戶的最終信用評(píng)分。

#根據(jù)變量計(jì)算分?jǐn)?shù)
def change_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
test1=data2.reset_index().drop('index',axis=1).copy()
test1=test1.iloc[:,[1,2,3,9,7]]
#計(jì)算test里面的分?jǐn)?shù)
test1['x1_可用額度比'] = pd.Series(change_score(test1['可用額度比'], cutx1, x1_revol))
test1['x2_年齡'] = pd.Series(change_score(test1['年齡'], cutx2, x2_age))
test1['x3_逾期30-59天筆數(shù)'] = pd.Series(change_score(test1['逾期30-59天筆數(shù)'], cutx3, x3_30))
test1['x4_逾期60-89天筆數(shù)'] = pd.Series(change_score(test1['逾期60-89天筆數(shù)'], cutx4, x4_60))
test1['x5_逾期90天筆數(shù)'] = pd.Series(change_score(test1['逾期90天筆數(shù)'], cutx5, x5_90))
test1['Score'] =test1['x1_可用額度比'] + test1['x2_年齡'] + test1['x3_逾期30-59天筆數(shù)'] + test1['x4_逾期60-89天筆數(shù)'] + test1['x5_逾期90天筆數(shù)'] + base
test1.to_csv('F:\ScoreData.csv', index=False)
image.png

這里得分越低的用戶,違約風(fēng)險(xiǎn)越大。評(píng)分卡建立后,應(yīng)通過設(shè)定cut-off準(zhǔn)入分?jǐn)?shù)將客群劃分為不同等級(jí)。這里的準(zhǔn)入分?jǐn)?shù)可以通過通過率和壞賬率評(píng)估模型在業(yè)務(wù)中的表現(xiàn)來設(shè)定,也需要結(jié)合政策、誤差等因素人工調(diào)整。下圖為測(cè)試集評(píng)分卡分?jǐn)?shù)分布情況。

評(píng)分卡分?jǐn)?shù)分布
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容