95年的今天國內(nèi)發(fā)行了第一張信用卡,那你會用數(shù)據(jù)模型分析信用卡客戶違約概率嗎

項目背景:

自1995年4月16日上海發(fā)不了中國第一張信用卡以來已有26年了,近些年越來越多的人使用信用卡。信用卡要求人們按時還款,若未按時還款,銀行將收取一定的利息獲益,因此各大銀行為了搶占市場,最大化發(fā)展客戶。但有一些客戶可能會違約使銀行利益受損,故控制違約情況顯得迫在眉睫。

本文通過預(yù)測某人在未來兩年內(nèi)遭遇財務(wù)困境的可能性,來提高自己在信用評分方面的水平。目標是建立一個借款人可以用來幫助做出最佳財務(wù)決策的模型。
本文主要從分析框架、數(shù)據(jù)處理和建立預(yù)測模型等幾個方面進行分析和介紹:

個人大數(shù)據(jù)學(xué)習(xí)筆記和經(jīng)典面試題整理,點擊此處免費領(lǐng)取

一、明確分析需求

1.1數(shù)據(jù)介紹

本數(shù)據(jù)來kaggle數(shù)據(jù)集:
提供了25萬借款人的歷史數(shù)據(jù),包括訓(xùn)練集、測試集以及數(shù)據(jù)集信息。

首先查看數(shù)據(jù)包含的文件:

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import os
for dirname, _, filenames in os.walk('GiveMeSomeCredit'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

結(jié)果:

GiveMeSomeCredit\cs-test.csv
GiveMeSomeCredit\cs-training.csv
GiveMeSomeCredit\Data Dictionary.xls
GiveMeSomeCredit\sampleEntry.csv

我們可以看到文件有訓(xùn)練集和測試集,以及一個資料字典,還有提交樣例。
查看一下資料字典里的信息:


主要是講的各字段所代表的名稱,含義和類型。
各字段代表的含義:

1.2明確分析思路

我們看到這些數(shù)據(jù),到底有什么用呢,如何去分析呢?
首先明確目的:信用卡數(shù)據(jù)的各個信息對我們分析有什么用,最終目的什么,可以得到什么結(jié)論?
目的:通過這些數(shù)據(jù)預(yù)測信用卡客戶違約的預(yù)測概率。
思路:通過分析數(shù)據(jù)之間的相關(guān)性,關(guān)聯(lián)性,進行特征分析,選擇合適的特征進行建模。
具體方法:查看各數(shù)據(jù)的統(tǒng)計信息,與是否逾期的關(guān)系,進行可視化表示,并得到相應(yīng)的一些結(jié)論。

1.3 數(shù)據(jù)探索

首先看一下訓(xùn)練集中的內(nèi)容:

df = pd.read_csv("GiveMeSomeCredit//cs-training.csv")
df.drop('Unnamed: 0',axis =1,inplace = True)
df.head()

為了看起來方便,將英文名替換成中文名


# 中文名替換
zh_label = ['目標變量','信用卡余額百分比','年齡','逾期30-59天的次數(shù)','每月開支占比','月收入','未償還債務(wù)','抵押貸款和房地產(chǎn)貸款的數(shù)量','借款人逾期60-89天的次數(shù)','家庭成員數(shù)目']
en_label = df.columns.values.tolist()
zh_label_dict = dict(zip(en_label,zh_label))
zh_label_dict
df.rename(columns =zh_label_dict ,inplace=True)
df.head()

查看一下數(shù)據(jù)的基本信息:
數(shù)據(jù)大小

df.shape

(150000, 11) 共有150000個數(shù)據(jù),特征向量有11個。

查看數(shù)據(jù)類型

df.dtypes.value_counts()
int64      7
float64    4
dtype: int64

一共有7個特征是整型,4個特征是浮點型。
數(shù)據(jù)信息

df.info()

觀察到部分數(shù)據(jù)有缺失,所以接下來需要對缺失值的處理

1.4數(shù)據(jù)清洗和處理

查看缺失值

df.isnull().sum()[df.isnull().sum() != 0]
月收入       29731
家庭成員數(shù)目     3924

可以看到月收入和家庭成員數(shù)目有缺失,一般數(shù)據(jù)缺失有幾種處理方法:

直接刪除
用眾數(shù)、中位數(shù)等進行替換
根據(jù)變量之間的相關(guān)關(guān)系填補缺失值
不過考慮到總數(shù)為15萬,家庭成員數(shù)目占比較小,缺失數(shù)據(jù)可以刪除。月收入應(yīng)當是一個重要的因素,且占比不算小,可以根據(jù)變量之間的相關(guān)關(guān)系填補缺失值。
采用隨機森林法:

# 用隨機森林對缺失值預(yù)測填充函數(shù)
def set_missing(df):
    # 把已有的數(shù)值型特征取出來
    process_df = df.iloc[:,[5,0,1,2,3,4,6,7,8,9]]
    # 分成已知該特征和未知該特征兩部分
    # dataframe.values獲取的是dataframe中的數(shù)據(jù)為數(shù)組array
    known = process_df[process_df.月收入.notnull()].values
    unknown = process_df[process_df.月收入.isnull()].values
    # X為已知MonthlyIncome的特征屬性值
    X = known[:, 1:]
    # y為結(jié)果標簽值MonthlyIncome
    y = known[:, 0]
    # X與y用于訓(xùn)練隨機森林模型,fit到RandomForestRegressor之中
    rfr = RandomForestRegressor(random_state=0, n_estimators=200,max_depth=3,n_jobs=-1)
    rfr.fit(X,y)
    # 用得到的模型進行未知特征值預(yù)測
    predicted = rfr.predict(unknown[:, 1:]).round(0)
    # 用得到的預(yù)測結(jié)果填補原缺失數(shù)據(jù)
    df.loc[(df.月收入.isnull()), '月收入'] = predicted
    return df
df=set_missing(df)              # 用隨機森林填補比較多的缺失值
df=df.dropna()                  # 刪除比較少的缺失值
df = df.drop_duplicates()       # 刪除重復(fù)項
df.info()
 0   目標變量            145563 non-null  int64  
 1   信用卡余額百分比        145563 non-null  float64
 2   年齡              145563 non-null  int64  
 3   逾期30-59天的次數(shù)     145563 non-null  int64  
 4   每月開支占比          145563 non-null  float64
 5   月收入             145563 non-null  float64
 6   未償還債務(wù)           145563 non-null  int64  
 7   逾期90天或以上的次數(shù)     145563 non-null  int64  
 8   抵押貸款和房地產(chǎn)貸款的數(shù)量   145563 non-null  int64  
 9   借款人逾期60-89天的次數(shù)  145563 non-null  int64  
 10  家庭成員數(shù)目          145563 non-null  float64

可以看到數(shù)量變成了145563個了。

觀察正負樣本數(shù)量是否大致相等

df.目標變量.value_counts()
0    135732
1      9831

可以看到大約為13比1的情況
個人大數(shù)據(jù)學(xué)習(xí)筆記和經(jīng)典面試題整理,點擊此處免費領(lǐng)取

二、異常值檢測

缺失值處理完畢后,我們還需要進行異常值處理。異常值是指明顯偏離大多數(shù)抽樣數(shù)據(jù)的數(shù)值,比如個人客戶的年齡為0時,通常認為該值為異常值。找出樣本總體中的異常值,通常采用離群值檢測的方法。

df["年齡"].describe()
count    145563.000000
mean         52.110701
std          14.567652
min           0.000000
25%          41.000000
50%          52.000000
75%          62.000000
max         107.000000

我們可以看到最小值為0,所以需要對其異常值處理。應(yīng)當刪掉此異常值。

df.drop(df[(df['年齡'] == 0)].index.tolist(),inplace = True)
df["年齡"].describe()
count    145562.000000
mean         52.111059
std          14.567062
min          21.000000
25%          41.000000
50%          52.000000
75%          62.000000
max         107.000000

刪掉之后最小值為21,符合數(shù)據(jù)事實。

對于其它的數(shù)據(jù),我們可以通過查看箱型圖的方式查看:

import matplotlib.pyplot as plt #導(dǎo)入圖像庫
fig=plt.figure(figsize=(10,5))
plt.rcParams['font.sans-serif'] = ['SimHei'] # 步驟一(替換sans-serif字體)
ax1=fig.add_subplot(131) 
ax1.boxplot(df['逾期30-59天的次數(shù)'])
ax1.set_title('逾期30-59天次數(shù)')
ax2=fig.add_subplot(132)
ax2.boxplot(df['逾期90天或以上的次數(shù)'])
ax2.set_title('逾期90天或以上的次數(shù)')
ax3=fig.add_subplot(133)
ax3.boxplot(df['借款人逾期60-89天的次數(shù)'])
ax3.set_title('借款人逾期60-89天的次數(shù)')
plt.show()

可以看到,逾期30-59天中出現(xiàn)了100天左右的數(shù)字,逾期90天和60-89天的次數(shù)也出現(xiàn)了這種情況。分析可知均存在96、98兩個異常值,因此予以剔除。同時會發(fā)現(xiàn)剔除其中一個變量的96、98值,其他變量的96、98兩個值也會相應(yīng)被剔除。

df =df[df['逾期30-59天的次數(shù)'] < 60]
fig=plt.figure(figsize=(10,5))
plt.rcParams['font.sans-serif'] = ['SimHei'] # 步驟一(替換sans-serif字體)
ax1=fig.add_subplot(131) 
ax1.boxplot(df['逾期30-59天的次數(shù)'])
ax1.set_title('逾期30-59天次數(shù)')
ax2=fig.add_subplot(132)
ax2.boxplot(df['逾期90天或以上的次數(shù)'])
ax2.set_title('逾期90天或以上的次數(shù)')
ax3=fig.add_subplot(133)
ax3.boxplot(df['借款人逾期60-89天的次數(shù)'])
ax3.set_title('借款人逾期60-89天的次數(shù)')
plt.show()

這些數(shù)據(jù)都正常了。

對于’信用卡余額百分比’,‘每月開支占比’,‘未償還債務(wù)’,‘月收入’,‘抵押貸款和房地產(chǎn)貸款的數(shù)量’等去除單側(cè)99%上部分異常值:

for variable in ['信用卡余額百分比','每月開支占比','月收入','未償還債務(wù)','抵押貸款和房地產(chǎn)貸款的數(shù)量']:
    df=df[df[variable]<df[variable].quantile(0.99)]
df.info()

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

3.1單變量分析

檢驗?zāi)繕俗兞康恼摌颖緮?shù)量是否大致相等。

grouped = df['目標變量'].value_counts()
print("逾期客戶占比:{:.2%}".format(grouped[1]/grouped[0]))

逾期客戶占比:6.29%,說明正負樣本數(shù)量不平衡,這個可以作為后續(xù)測試集的分類標準。
查看客戶年齡分布

fig = plt.figure()
fig,axes=plt.subplots(1,3,figsize=(10,5))
sns.distplot(df["年齡"],ax = axes[0],axlabel='所有客戶年齡分布')
sns.distplot(df.loc[df["目標變量"] == 0]["年齡"],ax = axes[1],axlabel='非違約客戶年齡分布')
sns.distplot(df.loc[df["目標變量"] == 1]["年齡"],ax = axes[2],axlabel='違約客戶年齡分布')

可以觀察到,所有的客戶類型都基本符合正太分布,符合統(tǒng)計類型。
再查看用戶是否違約和年齡段之間的關(guān)系:

import matplotlib.ticker as ticker
age_cut=pd.cut(df["年齡"],5)
age_cut_grouped=df["目標變量"].groupby(age_cut).count()
age_cut_grouped1=df["目標變量"].groupby(age_cut).sum()
df2=pd.merge(pd.DataFrame(age_cut_grouped), pd.DataFrame(age_cut_grouped1),right_index=True,left_index=True)
df2.rename(columns={"目標變量_x":"未違約客戶","目標變量_y":"違約客戶"},inplace=True)
df2.insert(2,"違約客戶率",df2["違約客戶"]/(df2["未違約客戶"]+df2["違約客戶"]))
ax2=df2["違約客戶率"].plot()
ax2.set_xticklabels(df2.index,rotation=15)
ax2.set_ylabel("違約客戶率")
ax2.set_title("違約客戶率隨年齡的變化趨勢圖")
plt.gca().xaxis.set_major_locator(ticker.MultipleLocator(1))

我們可以觀察到隨著年齡的增長,違約客戶率在降低,且38-72之間降低最快.說明年齡對于客戶是否違約是有相關(guān)性的.
月收入與是否違約的關(guān)系

income_cut=pd.cut(df["月收入"],18)
income_cut_grouped=df["目標變量"].groupby(income_cut).count()
income_cut_grouped1=df["目標變量"].groupby(income_cut).sum()
income_cut_grouped1
df3=pd.merge(pd.DataFrame(income_cut_grouped), pd.DataFrame(income_cut_grouped1),right_index=True,left_index=True)
df3.rename(columns={"目標變量_x":"未違約客戶","目標變量_y":"違約客戶"},inplace=True)
df3.insert(2,"違約客戶率",df3["違約客戶"]/(df3["未違約客戶"]+df3["違約客戶"]))
ax3=df3["違約客戶率"].plot(figsize=(15,6))
ax3.set_xticklabels(df3.index,rotation=15)
ax3.set_ylabel("違約客戶率")
ax3.set_title("違約客戶率隨月收入的變化趨勢圖")
plt.gca().xaxis.set_major_locator(ticker.MultipleLocator(1))

我們大概可以觀察出這個趨勢,隨著月收入的增加,違約客戶的比例在減少。

3.2 多變量分析

corr = df.corr()#計算各變量的相關(guān)性系數(shù)
xticks = list(corr.index)#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,linewidths=.5, annot_kws={'size': 9, 'weight': 'bold', 'color': 'blue'})
ax1.set_xticklabels(xticks, rotation=35, fontsize=10)
ax1.set_yticklabels(yticks, rotation=0, fontsize=10)
plt.show()

我們用熱力圖來表示不同變量之間的關(guān)系,單元格顏色越深,代表該單元格交叉的兩個變量相關(guān)性越強。
變量借款人逾期30-59天次數(shù)和借款人逾期60-89天的次數(shù)的相關(guān)系數(shù)最大為0.3,說明逾期一兩個月的人經(jīng)常也會逾期兩個月以上。
抵押貸款的數(shù)量和未償還債務(wù)相關(guān)系數(shù)為0.41,說明抵押貸款越多,未償還債務(wù)越多,符合邏輯。

四、變量選擇

特征變量選擇(排序)對于數(shù)據(jù)分析、機器學(xué)習(xí)從業(yè)者來說非常重要。好的特征選擇能夠提升模型的性能,更能幫助我們理解數(shù)據(jù)的特點、底層結(jié)構(gòu),這對進一步改善模型、算法都有著重要作用。至于Python的變量選擇代碼實現(xiàn)可以參考結(jié)合Scikit-learn介紹幾種常用的特征選擇方法。
在本文中,我們采用信用評分模型的變量選擇方法,通過WOE分析方法,即是通過比較指標分箱和對應(yīng)分箱的違約概率來確定指標是否符合經(jīng)濟意義。首先我們對變量進行離散化(分箱)處理。

4.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ù)
import matplotlib.pyplot as plt
import statsmodels.api as sm
import math
定義自動分箱函數(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(axis=1, level='min'))
    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

def self_bin(Y,X,cat):
    good=Y.sum()
    bad=Y.count()-good
    d1=pd.DataFrame({'X':X,'Y':Y,'Bucket':pd.cut(X,cat)})
    d2=d1.groupby('Bucket', as_index = True)
    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(axis=1, level='min'))
    print("=" * 60)
    print(d4)
    woe = list(d4['woe'].round(3))
    return d4, iv,woe

4.2 WOE

WoE分析, 是對指標分箱、計算各個檔位的WoE值并觀察WoE值隨指標變化的趨勢。其中WoE的數(shù)學(xué)定義是:
woe=ln(goodattribute/badattribute)
在進行分析時,我們需要對各指標從小到大排列,并計算出相應(yīng)分檔的WoE值。其中正向指標越大,WoE值越??;反向指標越大,WoE值越大。正向指標的WoE值負斜率越大,反響指標的正斜率越大,則說明指標區(qū)分能力好。WoE值趨近于直線,則意味指標判斷能力較弱。若正向指標和WoE正相關(guān)趨勢、反向指標同WoE出現(xiàn)負相關(guān)趨勢,則說明此指標不符合經(jīng)濟意義,則應(yīng)當予以去除。
woe函數(shù)實現(xiàn)在上一節(jié)的mono_bin()函數(shù)里面已經(jīng)包含,這里不再重復(fù)。

接下來,我進一步計算每個變量的Infomation Value(IV)。IV指標是一般用來確定自變量的預(yù)測能力。 其公式為:
IV=sum((goodattribute-badattribute)*ln(goodattribute/badattribute))
通過IV值判斷變量預(yù)測能力的標準是:

0.02: unpredictive
0.02 to 0.1: weak
0.1 to 0.3: medium
0.3 to 0.5: strong
0.5: suspicious
輸出圖像:


image.png

可以看出,每月開支占比、月收入、未償還債務(wù)、抵押貸款和房地產(chǎn)貸款的數(shù)量和家庭成員數(shù)目變量的IV值明顯較低,所以予以刪除。

五、模型分析

證據(jù)權(quán)重(Weight of Evidence,WOE)轉(zhuǎn)換可以將Logistic回歸模型轉(zhuǎn)變?yōu)闃藴试u分卡格式。引入WOE轉(zhuǎn)換的目的并不是為了提高模型質(zhì)量,只是一些變量不應(yīng)該被納入模型,這或者是因為它們不能增加模型值,或者是因為與其模型相關(guān)系數(shù)有關(guān)的誤差較大,其實建立標準信用評分卡也可以不采用WOE轉(zhuǎn)換。這種情況下,Logistic回歸模型需要處理更大數(shù)量的自變量。盡管這樣會增加建模程序的復(fù)雜性,但最終得到的評分卡都是一樣的。
在建立模型之前,我們需要將篩選后的變量轉(zhuǎn)換為WoE值,便于信用評分。

5.1 WOE轉(zhuǎn)換

我們已經(jīng)能獲取了每個變量的分箱數(shù)據(jù)和woe數(shù)據(jù),只需要根據(jù)各變量數(shù)據(jù)進行替換,實現(xiàn)代碼如下:

替換成woe函數(shù)

def replace_woe(series,cut,woe):
    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(woe[m])
        i += 1
    return list

我們將每個變量都進行替換,并將其保存到WoeData.csv文件中:

替換成woe

df['信用卡余額百分比'] = Series(replace_woe(df['信用卡余額百分比'], cutx1, woex1))
df['信用卡余額百分比']
df['年齡'] = Series(replace_woe(df['年齡'], cutx2, woex2))
df['逾期30-59天的次數(shù)'] = Series(replace_woe(df['逾期30-59天的次數(shù)'], cutx3, woex3))
df['每月開支占比'] = Series(replace_woe(data['每月開支占比'], cutx4, woex4))
df['月收入'] = Series(replace_woe(df['月收入'], cutx5, woex5))
df['未償還債務(wù)'] = Series(replace_woe(df['未償還債務(wù)'], cutx6, woex6))
df['逾期90天或以上的次數(shù)'] = Series(replace_woe(df['逾期90天或以上的次數(shù)'], cutx7, woex7))
df['抵押貸款和房地產(chǎn)貸款的數(shù)量'] = Series(replace_woe(df['抵押貸款和房地產(chǎn)貸款的數(shù)量'], cutx8, woex8))
df['借款人逾期60-89天的次數(shù)'] = Series(replace_woe(df['借款人逾期60-89天的次數(shù)'], cutx9, woex9))
df['家庭成員數(shù)目'] = Series(replace_woe(df['家庭成員數(shù)目'], cutx10, woex10))
df.to_csv('WoeData.csv', index=False)

5.2 Logisic模型建立

data = pd.read_csv('WoeData.csv')
應(yīng)變量
Y=data['SeriousDlqin2yrs']
自變量,剔除對因變量影響不明顯的變量

X=data.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1)
X1=sm.add_constant(X)
logit=sm.Logit(Y,X1)
result=logit.fit()
print(result.summary())

通過上圖可知,邏輯回歸各變量都已通過顯著性檢驗,滿足要求。

5.3 模型檢驗

到這里,我們的建模部分基本結(jié)束了。我們需要驗證一下模型的預(yù)測能力如何。我們使用在建模開始階段預(yù)留的test數(shù)據(jù)進行檢驗。通過ROC曲線和AUC來評估模型的擬合能力。
在Python中,可以利用sklearn.metrics,它能方便比較兩個分類器,自動計算ROC和AUC。
實現(xiàn)代碼:

#應(yīng)變量
    Y_test = test['SeriousDlqin2yrs']
    #自變量,剔除對因變量影響不明顯的變量,與模型變量對應(yīng)
    X_test = test.drop(['SeriousDlqin2yrs', 'DebtRatio', 'MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines', 'NumberOfDependents'], axis=1)
    X3 = sm.add_constant(X_test)
    resu = result.predict(X3)#進行預(yù)測
    fpr, tpr, threshold = roc_curve(Y_test, resu)
    rocauc = auc(fpr, tpr)#計算AUC
    plt.plot(fpr, tpr, 'b', label='AUC = %0.2f' % rocauc)#生成ROC曲線
    plt.legend(loc='lower right')
    plt.plot([0, 1], [0, 1], 'r--')
    plt.xlim([0, 1])
    plt.ylim([0, 1])
    plt.ylabel('真正率')
    plt.xlabel('假正率')
    plt.show()

從上圖可知,AUC值為0.85,說明該模型的預(yù)測效果還是不錯的,正確率較高。

六、信用評分

我們已經(jīng)基本完成了建模相關(guān)的工作,并用ROC曲線驗證了模型的預(yù)測能力。接下來的步驟,就是將Logistic模型轉(zhuǎn)換為標準評分卡的形式。

6.1 評分標準

依據(jù)以上論文資料得到:
a=log(p_good/P_bad)
Score = offset + factor * log(odds)
在建立標準評分卡之前,我們需要選取幾個評分卡參數(shù):基礎(chǔ)分值、 PDO(比率翻倍的分值)和好壞比。 這里, 我們?nèi)?00分為基礎(chǔ)分值,PDO為20 (每高20分好壞比翻一倍),好壞比取20。

    # 我們?nèi)?00分為基礎(chǔ)分值,PDO為20(每高20分好壞比翻一倍),好壞比取20。
    p = 20 / math.log(2)
    q = 600 - 20 * math.log(20) / math.log(2)
    baseScore = round(q + p * coe[0], 0)

個人總評分=基礎(chǔ)分+各部分得分

6.2 部分評分

下面計算各變量部分的分數(shù)。各部分得分函數(shù):

#計算分數(shù)函數(shù)
def get_score(coe,woe,factor):
    scores=[]
    for w in woe:
        score=round(coe*w*factor,0)
        scores.append(score)
    return scores

各項部分分數(shù)

    x1 = get_score(coe[1], woex1, p)
    x2 = get_score(coe[2], woex2, p)
    x3 = get_score(coe[3], woex3, p)
    x7 = get_score(coe[4], woex7, p)
    x9 = get_score(coe[5], woex9, p)

我們可以得到各部分的評分卡如圖所示


七、自動評分系統(tǒng)

根據(jù)變量計算分數(shù)

de f compute_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

我們來計算test里面的分數(shù):

    test1 = pd.read_csv('TestData.csv')
    test1['BaseScore']=Series(np.zeros(len(test1)))+baseScore
    test1['x1'] = Series(compute_score(test1['RevolvingUtilizationOfUnsecuredLines'], cutx1, x1))
    test1['x2'] = Series(compute_score(test1['age'], cutx2, x2))
    test1['x3'] = Series(compute_score(test1['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, x3))
    test1['x7'] = Series(compute_score(test1['NumberOfTimes90DaysLate'], cutx7, x7))
    test1['x9'] = Series(compute_score(test1['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, x9))
    test1['Score'] = test1['x1'] + test1['x2'] + test1['x3'] + test1['x7'] +test1['x9']  + baseScore
    test1.to_csv('ScoreData.csv', index=False)

批量計算的部分分結(jié)果:


好了, 本文就寫到這了,都看到這里了不點個贊嗎?
個人大數(shù)據(jù)學(xué)習(xí)筆記和經(jīng)典面試題整理,點擊此處免費領(lǐng)取

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

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

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