数据分析案例(四)——评分卡模型(四)

2020-05-17  本文已影响0人  番茄酱的汪

一、建模思路

信用评分卡.jpg

二、数据集介绍

givemesomecredit --Kaggle数据集
数据来自Kaggle的Give Me Some Credit,有15万条的样本数据,大致情况如下:
数据属于个人消费类贷款,只考虑信用评分最终实施时能够使用到的数据应从如下一些方面获取数据:
基本属性:包括了借款人当时的年龄。
偿债能力:包括了借款人的月收入、负债比率。
信用往来:两年内35-59天逾期次数、两年内60-89天逾期次数、两年内90天或高于90天逾期的次数。
财产状况:包括了开放式信贷和贷款数量、不动产贷款或额度数量。
贷款属性:暂无。
其他因素:包括了借款人的家属数量(不包括本人在内)。
时间窗口:自变量的观察窗口为过去两年,因变量表现窗口为未来两年。

三、具体步骤与代码

3.1 数据描述

df.rename(columns = {'SeriousDlqin2yrs':'y'},inplace = True)
df.drop(columns = 'Unnamed: 0',inplace = True) #因为id没有什么意义,下面还要直接去重
df.info()
结果.png
(df['y'].value_counts()[1])/len(df)

0.06684

其他的数据描述,例如绘制条形图、相关性检查就不再这里写出来了。

3.2 数据清洗

3.2.1 去重、缺失值处理

# 去重
dfana = df.copy()
dfana.drop_duplicates(inplace = True)
dfana.reset_index(inplace = True)
# 缺失值补充
dfana.isnull().mean()
结果2.png
dfana[dfana['MonthlyIncome'].isnull()].y.value_counts()
image.png
# 对NumberOfDependents进行缺失值填补
dfana['NumberOfDependents']=Fillna(dfana['NumberOfDependents'],repval ='random')

3.2.2 异常值处理

dfana = dfana[dfana.age > 0]
dfana = dfana[(dfana['NumberOfTime30-59DaysPastDueNotWorse'] < 90)]
dfana.loc[(dfana.RevolvingUtilizationOfUnsecuredLines > 30),'RevolvingUtilizationOfUnsecuredLines'] = 0.5
dfana.loc[(dfana.DebtRatio > 2),'DebtRatio'] = 0.5

3.3 不平衡样本处理

注意:不平衡样本处理应该在分箱之前,因为分箱之后某些信息会缺失,所以按照badrate来平衡样本。

# 采用分层抽样,1:5的比例进行下采样
G_train = dfana[dfana.y == 0]
B_train = dfana[dfana.y == 1]
### 对好样本进行抽样,抽样个数选择坏样本个数的5倍
G_train_sample = G_train.sample(n=B_train.shape[0] * 5, frac=None, replace=False, weights=None, random_state=101, axis=0)
dfana_t = []
dfana_t = pd.concat([G_train_sample,B_train])
dfana_t.reset_index(inplace = True,drop = True)
dfana_t.drop(columns = 'index',inplace = True)

3.4 分箱处理

  1. 生成交叉表,计算badrate:
    dftbl = pd.crosstab(dfana[colname], dfana[target])
    dftbl.reset_index(inplace = True)
    dftbl['badrate'] = dftbl[1] / (dftbl[0] + dftbl[1])
  1. 需要提前处理badrate极端的组别,badrate = 0 or 1,这部分提前与上下组别合并。
  2. 最好定义一个dataframe记录需要转变前的colname,与需要转变后的colname
# 初始化的转换表格就是自己本身
dfres = pd.DataFrame({colname : dftbl[colname], 'trans' : dftbl[colname]})
# 找到需要转换的变量特征,利用dfres将原来的table转变一下
dfres.loc[i, 'trans'] = dfres.loc[i - 1, 'trans']
dftbl['anacol'] =  dfres.trans
# 转变了之后利用groupby再次合并一次
dftbl = dftbl.groupby('anacol', as_index = False, 
                              observed = True).agg('sum')
  1. 计算相邻两个单元格的卡方值
for i in range(N_levels - 1): 
        dftbl.loc[i, 'chi2'] = ss.chi2_contingency(dftbl.loc[i : i + 1, [0, 1]])[0] 
  1. 找到最小的卡方值,进行向上或者向下合并,合并了之后还需要重新计算其卡方值
dftbl.loc[minindex, 'chi2'] = ss.chi2_contingency(dftbl.loc[minindex : minindex + 1,
                                                                    [0, 1]])[0]

3.5 WOE\IV值

新增一个计算WOE和IV值的函数,计算分箱之后的woe值,和整体变量的iv值,然后进行反复筛选。
主要代码:

    dftbl = pd.crosstab(colname.fillna('NA'), target, normalize = 'columns') #normalize是计算target中的各项频率!数量/列的总和
    # 也就是goodpct,badpct
    dftbl.columns = ['goodpct', 'badpct']
    dftbl['WOE'] = np.log(dftbl.goodpct / dftbl.badpct) * 100
    IV = sum((dftbl.goodpct - dftbl.badpct) * dftbl.WOE) / 100
image.png image.png image.png image.png image.png image.png image.png image.png

3.6 切分训练集和测试集

from sklearn.model_selection import train_test_split
train_df, test_df = train_test_split(dfana_fit,test_size = 0.3)
train_df.shape, test_df.shape

3.7 特征选择(选用)

image.png
from statsmodels.stats.outliers_influence import variance_inflation_factor
colnames = list(model.params.index)
colnames.remove('Intercept')
train_X_M = np.matrix(train_df[colnames])

VIF_list = [variance_inflation_factor(train_X_M, i) for i in range(train_X_M.shape[1])]
VIF_list

[1.345451226908903,
1.2336645504356645,
1.203776578215364,
1.2737738281637017,
1.1334798511412756,
1.0174816425613178,
1.0462200835734954,
1.0972902825775086,
1.0547503741366757]

3.8 评价模型

from sklearn.metrics import auc,roc_curve, roc_auc_score
### 计算AUC值
print('训练集的auc为:{}'.format(roc_auc_score(train_df.y,train_predict)))
print('测试集的auc为:{}'.format(roc_auc_score(test_df.y, predictions)))

训练集的auc为:0.8320949945565318
测试集的auc为:0.8307774122803272

3.9 转换成分值

利用公式进行求解:评分卡模型(三)
按照公式求出Factor和offset,当然自己要规定PDO(odds比增加一倍时候要增加的分数),β是建模的系数。

    factor = pdo/np.log(2)
    offset = basescore - factor * np.log(baseodds)
    dfres['cardscore'] = round(offset / n - factor * (para.Intercept / n + dfres.beta * dfres.WOE))
分数特征.png

3.10 KS指标

上一篇 下一篇

猜你喜欢

热点阅读