贷款客户违约预测模型

作者: Ziger丶 | 来源:发表于2018-08-10 18:01 被阅读331次

    背景:根据已有贷款客户的还款情况数据,以预测客户是否违约,提前预警。
    数据:某融资担保公司所拥有的数据,包括基本身份信息,每月还款与支出情况,行业、缴款方式、缴款记录、时间、频率等信息。
    目标:建立多个机器学习模型(SVM,逻辑回归,随机森林等)。选择出稳定得分率较高的模型,以预测违约情况。

    违约分析

    【一】 建模思路

    确定本次项目的流程。
    思路流程

    本次已有贷款客户数据,需要选择出相关性最强的维度,对客户是否违约进行二分类。建立模型后,预测客户是否违约,以提前预警。


    【二】 数据清洗

    从数据库中提取出相应的数据,观察数据。

    客户数据(脱敏)

    观察数据集后发现部分数据是半结构化数据,需要进行特征抽象。部分数据可能存在缺失,我们判定贷款申请人是否违约是一个 二元分类 问题。可以通过一个分类算法来处理。

    1>查看数据集合维度
    data.dtypes.value_counts()
    

    (110292, 42)

    2>查看每列属性缺失值的比例

    因为数据集缺失值较多的特征对模型预测意义不大,故应先处理。

    check_null = data.isnull().sum().sort_values(ascending=False)/float(len(data)) 
    print(check_null[check_null > 0.2]) # 查看缺失比例大于20%的属性。
    

    处理后可发现,本次数据集数据量完整不需要删除缺失较多的数据。
    如果缺失值对属性来说是有意义的,还得细分缺失值对应的属性是数值型变量或是分类类型变量。

    3>同值化处理

    如果某个变量大部分的观测都是相同的特征,那么这个特征或者输入变量就无法用来区分预测值。

    data = data.loc[:,data.apply(pd.Series.nunique) != 1]
    data.shape
    

    (110292, 32)

    4>数据过滤

    结合业务知识,将一般无关或对构建预测模型没有意义的属性整合入drop_list,后删除drop_list以提高数据置信度。

    data.drop(drop_list, axis=1, inplace=True)
    

    (110292, 22)

    5>将数据做预处理

    将所有字符串形式的属性转换为数字形式,将部分连续变量转换为离散变量,再对部分数据做归一化。

    def Sigmoid (X):
        return (1.0 / (1 + np.exp(-float(X)));
    
    def Replace (X,columns):
        a = X.groupby([columns],as_index=False)[columns].agg({'cnt':'count'})
        for i in a[columns]:
            X[columns] = X[columns].replace(i,a[(a[columns]== i )].index.tolist()[0])
        return (X)
    
    def Quota (X):
        X['信用额度']=X['信用额度']*(10**-4)
        return (X)
    
    def Age (X):
        a = X.groupby(['年龄'],as_index=False)['年龄'].agg({'cnt':'count'})
        for i in a['年龄']:
            if i < 30:
                X['年龄'].replace(i,0)
            if 30 <= i <40:
                X['年龄'].replace(i,1)
            if 40 <= i :
                X['年龄'].replace(i,2)
        return (X)
    

    清洗完后数据:

    各个维度方差验证

    【二】 特征工程

    1>特征衍生

    为了提高对贷款客户的预测,根据业务经验生成新的特征。
    例如:将每月分期应还金额减去上一月应还金额,再除以当月实际归还的天数,生成新特征,代表客户每月还款支出的变化,值越大意味着贷款人的偿债压力越来越大,违约的可能性越大。

    2>特征缩放

    采用的是标准化方法,调用scikit-learn模块preprocessing的子模块StandardScaler。
    preprocessing.StandardScaler类可以用来计算数据矩阵的均值和标准差,而且这个类用起来更方便

    from sklearn import preprocessing
    sc =StandardScaler()  # 初始化缩放器
    data_ml_df[col] =sc.fit_transform(data_ml_df[col])  #对数据进行标准化
    
    3>特征选择

    选出与目标变量相关性较高的特征。递归特征消除 (RFE)筛选15个与目标变量相关性最强的特征,去除不相关特征以降低学习的难度而达到首次降维.

    def RFE (X,Y,n):
        from sklearn.linear_model import LogisticRegression
        from sklearn.feature_selection import RFE
        model = LogisticRegression()
        # 建立递归特征消除筛选器
        rfe = RFE(model, n_features_to_select=n)     #通过递归选择特征,选择n个特征
        rfe = rfe.fit(X,Y)
        return (rfe.n_features_ , rfe.estimator_ , rfe.support_ , rfe.ranking_)   #ranking 为 1代表被选中,其他则未被代表未被选中
    

    运用PCA进行主成分分析。PCA可能会提高模型准确率,但是可解释性会下降,根据具体情况选择使用。

    def PCA(data):
        from sklearn.decomposition import PCA
        pca=PCA(n_components=None, copy=True, whiten=False)
        pca.fit(data)
        return(pca.components_ ,pca.explained_variance_ratio_)
    
    #pca.components_返回模型的各个特征向量
    #pca.explained_variance_ratio_返回各个成为各自的方差百分比(贡献率)
    
    4>相关性分析

    选择出是否违约相关性最强的24个维度进行分析。

    import matplotlib.pyplot as plt  
    import seaborn as sns 
    import numpy as np
    import pandas as pd
    
    plt.rcParams['font.sans-serif']=['SimHei']                
    plt.rcParams['axes.unicode_minus']=False
    corrmat = data.corr()  
    k = 24
    plt.figure(figsize=(12,9))
    cols = corrmat.nlargest(k, '是否违约')['是否违约'].index                       
    cm = np.corrcoef(data[cols].values.T)
    sns.set(font_scale=1.25,font='SimHei')                                   
    hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f',cmap='BuGn_r',annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values)
    plt.show()
    
    相关性较强的维度

    【三】 模型训练

    1>数据选择

    在观察预测值Y之后发现,违约与按时还款差值过大,这时带入模型考虑是否准备不同的数据集合以提高准确性。
    准备data1 违约量按照百分比存在,data2违约量等同于按时还款量。

    def Breach(IO):          #违约的数据
        a = X.groupby(['是否违约'],as_index=False)['是否违约'].agg({'cnt':'count'})
        X=pd.read_excel(IO)
        X['是否违约'] = X['是否违约'].replace(0,np.NaN)
        X_breach= X.dropna(axis=0,how='any')
        return (X_breach)
    
    def Abiding(IO):         #按时还款的数据
        X=pd.read_excel(IO)   
        X['是否违约'] = X['是否违约'].replace(1,np.NaN)
        X_abiding = X.dropna(axis=0,how='any')
        return (X_abiding)
    
    2>构建分类器训练

    采用交叉验证法划分数据集,将数据划分为3部分:训练集、验证集和测试集。

    from sklearn import cross_validation 
    
    def Data1(IO):           #原始数据
        X=pd.read_excel(IO)
        Y1 = X['是否违约']
        X1 = X.drop(['是否违约'],axis = 1)
        X1_train, X1_test, y1_train, y1_test = \
            cross_validation.train_test_split( X1, Y1, test_size=0.3, random_state=0)
        return (X1_train, X1_test, y1_train, y1_test)
    
    def Data2(X_breach,X_abiding):          #同样数量  
        X_abiding = X_abiding.sample(n=len(X_breach))
        S = pd.concat([X_breach,X_abiding],axis = 0)
        S = S.sample(frac=1).reset_index(drop=True)
        Y2 = S['是否违约']
        X2 = S.drop(['是否违约'],axis = 1)
        X2_train, X2_test, y2_train, y2_test = \
            cross_validation.train_test_split( X2, Y2, test_size=0.3, random_state=0)
        return (X2_train, X2_test, y2_train, y2_test)  
    

    本次交叉验证的比例为7:3

    3>建立模型

    二分类问题,首先选择逻辑回归,随机森林与支持向量机进行验证。
    后根据具体情况可以考虑Adaboost,朴素贝叶斯等。

    from sklearn.metrics import accuracy_score
           
    def RF(X_train, X_test, y_train, y_test):    #随机森林 
        from  sklearn.ensemble  import  RandomForestClassifier
        model= RandomForestClassifier(n_estimators=100)
        model.fit(X_train, y_train)
        predicted= model.predict(X_test)
        score = accuracy_score(y_test, predicted)
        return (score)
    
    def Svm(X_train, X_test, y_train, y_test):   #支持向量机
        from sklearn import svm
        model = svm.SVC(kernel='rbf')
        model.fit(X_train, y_train)    
        predicted= model.predict(X_test)
        score = accuracy_score(y_test, predicted)
        return (score)    
    
    def LR(X_train, X_test, y_train, y_test):   #逻辑回归
        from sklearn.linear_model import LogisticRegression
        lor = LogisticRegression(penalty='l1',C=100,multi_class='ovr') 
        lor.fit(X_train, y_train)
        predicted= lor.predict(X_test)
        score = accuracy_score(y_test, predicted)
        return (score)    
    
    def SGD(X_train, X_test, y_train, y_test):      #随机梯度下降
        from sklearn.linear_model import SGDClassifier
        sgdv = SGDClassifier(penalty='l1')
        sgdv.fit(X_train,y_train)
        predicted = sgdv.predict(X_test)
        score = accuracy_score(y_test, predicted)
        return (score) 
    

    尝试不同算法后得分如下

    data1 : 百分比       data2 : 同等数量 
    #随机森林得分: data1 : 0.8192222222222222 data2 : 0.6958814665996986 
    #支持向量机 rbf 得分: data1 : 0.7856666666666666 data2 : 0.5228528377699648
    #逻辑回归得分: data1 : 0.7845555555555556 data2 : 0.5979407332998493 
    #随机梯度下降得分: data1 : 0.7457777777777778 data2 : 0.5507282772476143 
    

    比较后模型后,优化参数,提高准确性。


    【四】 分析结果

    训练模型得分不太满意,只有随机森林得分较高。特征工程程度加深的化,可能有助于提高模型得分。
    可尝试模型融合,不同模型投票后,集成学习有助于值的预测。
    百分比数据量的结果明显优于等比例数据量。

    相关文章

      网友评论

      • yemoumou:弃我去者,昨日之日不可留;-简书朋友你好,我是币圈一老友,我的写作方向是区块链和数字货币,初到简书,望多多关照。互粉互赞,已赞,期待您的回赞哦。-֒怅容,箹�
      • 蚂蚁不在线:无脑lightgbm呀

      本文标题:贷款客户违约预测模型

      本文链接:https://www.haomeiwen.com/subject/ltylbftx.html