精华内容
下载资源
问答
  • 信用评分开发流程

    2019-08-29 10:23:59
    信贷评分卡:以分数的形式来衡量用户风险的一种模型策略。通常,分数越低,风险越高。...开发流程: 1、数据选取,数据选取设计三个重要方面:第一,能否获取到用户尽量全的数据指标,数据是建模的基础,...

    信贷评分卡:以分数的形式来衡量用户风险的一种模型策略。通常,分数越低,风险越高。

    分类:根据使用场景分为反欺诈评分卡、申请评分卡、行为评分卡、催收评分卡。

    特性:可解释性、稳定性、预测能力、识别效果、等价于逾期概率

    作用:参与决策、额度策略依据、利率策略依据

    常用模型:logistic回归

    开发流程

    1、数据选取,数据选取设计三个重要方面:第一,能否获取到用户尽量全的数据指标,数据是建模的基础,也是贯穿整个建模过程的主线;第二,好坏用户定义,主要是借鉴用户还款以及逾期的滚动率分析来判断好坏界定的阈值;第三,观察期和表现期的确定,主要是通过账龄分析来判定坏用户充分暴露所需要的时间周期

    2、变量筛选,通常我们的数据集可能会包含成百上千的指标变量,但是这些变量并不是全部都要纳入评分建模,或者说本身有些‘收益’较小的变量提前舍去更方便后面的建模工作,主要的变量筛选主要有随机森林、xgboost、IV值计算、losso回归、逐步回归、相关性分析等;

    3、woe变换,对筛选的关键性指标进行分箱处理(woe变换),主要的分箱方法主要有等频分箱、等距分箱、卡方分箱、决策树分箱等;

    4、logistic回归,对分箱完成的变量进行logistic回归建模,剔除参数估计为负数的变量,重新进行建模,直至参数估计全部为正数;

    5、变量分数输出,确定评分卡刻度(基础分以及补偿),对每个变量计算并输出划分区间以及分数,对业务上解释不通的评分变量寻找原因、替代变量或者舍去,返回至logistic回归;

    6、模型评价,通过评价指标(ks、auc、psi等)评价模型的识别能力以及泛化效果。

    7、结合业务,进行用户等级划分,制定额度以及利率策略。
    在这里插入图片描述
    这里只讲解了大致的流程,让大家有个宏观的评分建模逻辑框架。这里面牵扯到比较多的理论知识,包括滚动率分析、账龄分析、logistic回归理论、评分卡计算分数理论、IV值计算等都会以专题的形式讲到。

    展开全文
  • 信用评分开发流程

    2018-04-08 22:44:05
    信用评分卡原理以及开发流程,关键点的阐述。大学课件
  • 这里用的也是与FICO评分类似的个人信用评分工具。 FICO评分的只要思路是:多大量拥有多个属性的用户数据进行收集/分析/转换,使用各项统计指标(如相关系数/卡方校验/方差膨胀系数等)对属性进行取舍/复制/组合,...

    以支付宝的芝麻信用为例,其分值范围在350-950分。一般认为分值越高,信用越好,个人业务的违约率越低。这里用的也是与FICO评分类似的个人信用评分工具。

    FICO评分的只要思路是:多大量拥有多个属性的用户数据进行收集/分析/转换,使用各项统计指标(如相关系数/卡方校验/方差膨胀系数等)对属性进行取舍/复制/组合,最终得到一个量化的/综合的/可用于对比的分值。分值的高低,一方面反映了用户历史信用记录的好坏,另一方面暗示了未来违约可能性的大小。

    这里使用到的原始数据主要包括客户的个人信息(包括性别/年龄/工作岗位/婚姻情况/学历状况等)/账户信息(包括各种账户的数量/存贷款余额等),以及该客户是否存在违约的分类标签。

    数据集经过处理后,需要经过数据分箱/属性选择以及离散分类标签与连续信用评分结果的转换等过程。

    数据集的下载
    链接: https://pan.baidu.com/s/1xh1kjo6waZZEPrxJFrwCng 密码: u744

    一.导入数据

    #导入包
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    #查看原始数据
    data = pd.read_csv('credit.csv')
    print('原始数据概况')
    data.info()
    #数据为12.6M,11个属性,有两个属性MonthlyIncome和NumberOfDependents中有空值
    

    数据为12.6M,有11个属性,有两个属性MonthlyIncome和NumberOfDependents中有空值
    在这里插入图片描述
    二.数据清洗
    因为MonthlyIncome和NumberOfDependents中有缺失值,需要对其进行处理,常用的方法1.有上下值填入空白处;2.属性均值填入空白处。但是各有它的缺点。这里定义了一个set_missing的函数,用来填充随机森林回归算法对缺失值进行填充。

    #进行数据清洗
    #用随机森林方法对MonthlyIncome缺失值进行预测填充,这里定义了set_missing函数
    from sklearn.ensemble import RandomForestRegressor
    def set_missing(df):
        print('随机森林回归填充0值:')
        process_df = df.iloc[:,[5,0,1,2,3,4,6,7,8,9]]
        #把第5列的MonthlyIncome提前到第0列,作为一个标签,便于后续划分数据
        #分成有数值缺失值两组
        known = process_df.loc[process_df['MonthlyIncome']!=0].values
        unknown = process_df.loc[process_df['MonthlyIncome']==0].values
        X = known[:,1:]
        y = known[:,0]
        #用x,y训练随机森林回归算法
        rfr = RandomForestRegressor(random_state=0,n_estimators=200,max_depth=3,n_jobs=-1)
        rfr.fit(X,y)
        #得到的模型进行缺失值预测
        predicted = rfr.predict(unknown[:,1:]).round(0)
        #得到的预测结果填补原缺失数据
        df.loc[df['MonthlyIncome'] == 0,'MonthlyIncome'] = predicted
        return df
    

    定义outlier_processing函数,用于对属性中的离群数据点进行删除处理
    这里用到的方法是数据分箱:将属性的取值分成若干段(箱体),落在同一个箱体范围内的数据,用一个统一的数值代替。

    #对属性中的异常值进行删除处理,找出离群点,先计算最大和最小阈值作为删除标准
    #最小阈值 = 第一四位点 - 1.5*(第三四分位点 - 第一四分位点)
    #最大阈值 = 第三四位点 + 1.5*(第三四分位点 - 第一四分位点)
    #   <最小阈值  和  >最大阈值的行将会被删除
    #定义了outlier_processing函数,用于处理离群数据点
    
    def outlier_processing(df,cname):
        s = df[cname]
        onequater = s.quantile(0.25)
        threequater = s.quantile(0.75)
        irq = threequater - onequater
        min = onequater - 1.5*irq
        max = threequater + 1.5*irq
        df = df[df[cname]<=max]
        df = df[df[cname]>=min]
        return df
    

    MonthlyIncome原始分布图和处理后分布图

    #对MonthlyIncome列进行数据整理
    print('MonthlyIncome属性离群点原始分布:')
    data[['MonthlyIncome']].boxplot()
    plt.savefig('MonthlyIncome1.png',dpi = 300,bbox_inches = 'tight')
    plt.show()
    print('删除离群点,填充缺失数据:')
    data = outlier_processing(data, 'MonthlyIncome')#删除离群点
    data = set_missing(data)#填充缺失数据
    print('处理MonthlyIncome后数据概况:')
    data.info()#查看整理后数据
    #图像显示
    data[['MonthlyIncome']].boxplot()#箱线图
    plt.savefig('MonthlyIncome2.png',dpi = 300,bbox_inches = 'tight')
    plt.show()
    

    在这里插入图片描述

    删除离群点,填充缺失数据后,数据集少了2M
    在这里插入图片描述

    同理,对其他属性进行离群点处理

    #同理,对其他属性进行离群点处理
    data = outlier_processing(data, 'age')
    data = outlier_processing(data, 'RevolvingUtilizationOfUnsecuredLines')
    data = outlier_processing(data, 'DebtRatio')
    data = outlier_processing(data, 'NumberOfOpenCreditLinesAndLoans')
    data = outlier_processing(data, 'NumberRealEstateLoansOrLines')
    data = outlier_processing(data, 'NumberOfDependents')
    
    

    对于三个取值过于集中的属性进行手工处理

    #三个取值过于集中的属性,三个四分位点的值相等,直接用outlier_processing的函数会导致所有值被删除
    #因此对这三个属性进行手工处理
    
    features = ['NumberOfTime30-59DaysPastDueNotWorse','NumberOfTime60-89DaysPastDueNotWorse','NumberOfTimes90DaysLate']
    features_labels = ['30-59days','60-89days','90+days']
    print('三个属性的原始分布:')
    data[features].boxplot()
    plt.xticks([1,2,3],features_labels)
    plt.savefig('三个属性的原始分布', dpi = 300 ,bbox_inches = 'tight')
    plt.show()
    
    print('删除离群点后:')
    data = data[data['NumberOfTime30-59DaysPastDueNotWorse']<90]
    data = data[data['NumberOfTime60-89DaysPastDueNotWorse']<90]
    data = data[data['NumberOfTimes90DaysLate']<90]
    
    data[features].boxplot()
    plt.xticks([1,2,3],features_labels)
    plt.savefig('三个属性的整理后分布', dpi = 300 ,bbox_inches = 'tight')
    plt.show()
    print('处理离群点后数据概况:')
    data.info()
    

    在这里插入图片描述
    在这里插入图片描述

    #生成数据集和测试集
    from sklearn.model_selection import train_test_split
    #原始值0为正常,1为违约。因为习惯上信用评分越高,违约的可能越小,所以将原始值0和1置换
    data['SeriousDlqin2yrs'] = 1-data['SeriousDlqin2yrs']
    Y = data['SeriousDlqin2yrs']
    X = data.iloc[:,1:]
    
    #拆分训练集和数据集
    X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.3,random_state = 0)
    
    train = pd.concat([Y_train,X_train],axis = 1)
    test = pd.concat([Y_test,X_test],axis = 1)
    clasTest = test.groupby('SeriousDlqin2yrs')['SeriousDlqin2yrs'].count()
    print('训练集数据')
    print(train.shape)
    print('测试集数据')
    print(test.shape)
    

    在这里插入图片描述
    三.属性选择
    除了用相关性分析排除绝对值较小的属性外,可通过WoE(Weight of Evidence):迹象权重 与 IV(Information Value):信息值两个指标来考察某个属性对于目标变量影响的重要程度,从而决定属性的取舍。

    这两个指标的计算公式如下:
    WoE = In(pctlGood/pctlBad)
    MIV = WoE*(pctlGood-pctlBad)
    IV = ∑ MIV

    信息值IV的取值与要研究的目标变量之间相关性强弱的关系是:
    0<IV<0.02极弱
    0.02<=IV<0.1弱
    0.1<=IV<0.03一般
    0.3<=IV<0.5强
    0.5<=IV<1.0很强

    #对属性进行分箱,并计算WOE和IV值

    #对属性进行分箱,并计算WOE和IV值
    def mono_bin(res,feat,n = 10):
        good = res.sum()
        bad = res.count()-good
        d1 = pd.DataFrame({'feat':feat,'res':res,'Bucket':pd.cut(feat,n)})
        d2 = d1.groupby('Bucket',as_index = True)
        d3 = pd.DataFrame(d2.feat.min(),columns = ['min'])
        d3['min'] = d2.min().feat
        d3['max'] = d2.max().feat
        d3['sum'] = d2.sum().res
        d3['total'] = d2.count().res
        d3['rate'] = d2.mean().res
        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_values(by = 'min'))
        cut = []
        cut.append(float('-inf'))
        for i in range(1,n):
            qua = feat.quantile(i/(n))
            cut.append(round(qua,4))
        cut.append(float('inf'))
        woe = list(d4['woe'].round(3))
        return d4,iv,cut,woe
    
    def self_bin(res,feat,cat):
        good = res.sum()
        bad = res.count()-good
        d1 = pd.DataFrame({'feat':feat,'res':res,'Bucket':pd.cut(feat,cat)})
        d2 = d1.groupby('Bucket',as_index = True)
        d3 = pd.DataFrame(d2.feat.min(),columns = ['min'])
        d3['min'] = d2.min().feat
        d3['max'] = d2.max().feat
        d3['sum'] = d2.sum().res
        d3['total'] = d2.count().res
        d3['rate'] = d2.mean().res
        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_values(by = 'min'))
        woe = list(d4['woe'].round(3))
        return d4,iv,woe
    
    

    将各个属性按照指定间隔进行分箱,这里定义了cutx3/6/7/8/910分箱

    pinf = float('inf')
    ninf = float('-inf')
    dfx1,ivx1,cutx1,woex1 = mono_bin(train['SeriousDlqin2yrs'],train['RevolvingUtilizationOfUnsecuredLines'],n = 10)
    #显示RevolvingUtilizationOfUnsecuredLines分箱和WOE信息
    print('='*60)
    print('显示RevolvingUtilizationOfUnsecuredLines分箱和WOE信息:')
    print(dfx1)
    dfx2,ivx2,cutx2,woex2 = mono_bin(train['SeriousDlqin2yrs'],train['age'],n = 10)
    dfx4,ivx4,cutx4,woex4 = mono_bin(train['SeriousDlqin2yrs'],train['DebtRatio'],n = 10)
    dfx5,ivx5,cutx5,woex5 = mono_bin(train['SeriousDlqin2yrs'],train['MonthlyIncome'],n = 10)
    #对3,6,7,8,9,10列数据进行指定间隔分箱
    cutx3 = [ninf,0,1,3,5,pinf]
    cutx6 = [ninf,1,2,3,5,pinf]
    cutx7 = [ninf,0,1,3,5,pinf]
    cutx8 = [ninf,0,1,2,3,pinf]
    cutx9 = [ninf,0,1,3,pinf]
    cutx10 = [ninf,0,1,2,3,5,pinf]
    
    #按照cutx3指定的间隔把NumberOfTime30-59DaysPastDueNotWorse属性分成5段
    dfx3,ivx3,woex3 = self_bin(train['SeriousDlqin2yrs'],train['NumberOfTime30-59DaysPastDueNotWorse'],cutx3)
    #显示NumberOfTime30-59DaysPastDueNotWorse分箱和woe信息:
    print('='*60)
    print('NumberOfTime30-59DaysPastDueNotWorse分箱和woe信息:')
    print(dfx3)
    dfx6,ivx6,woex6 = self_bin(train['SeriousDlqin2yrs'],train['NumberOfOpenCreditLinesAndLoans'],cutx6)
    dfx7,ivx7,woex7 = self_bin(train['SeriousDlqin2yrs'],train['NumberOfTimes90DaysLate'],cutx7)
    dfx8,ivx8,woex8 = self_bin(train['SeriousDlqin2yrs'],train['NumberRealEstateLoansOrLines'],cutx8)
    dfx9,ivx9,woex9 = self_bin(train['SeriousDlqin2yrs'],train['NumberOfTime60-89DaysPastDueNotWorse'],cutx9)
    dfx10,ivx10,woex10 = self_bin(train['SeriousDlqin2yrs'],train['NumberOfDependents'],cutx10)
    
    

    在这里插入图片描述

    对求出的IV属性进行画图

    #按照iv选取属性
    ivlist = [ivx1,ivx2,ivx3,ivx4,ivx5,ivx6,ivx7,ivx8,ivx9,ivx10]
    index = ['x1','x2','x3','x4','x5','x6','x7','x8','x9','x10']
    fig1 = plt.figure(1)
    ax1 = fig1.add_subplot(1,1,1)
    x = np.arange(len(index))+1
    ax1.bar(x,ivlist,width = 0.48,color = 'yellow',alpha = 0.5)
    ax1.set_xticks(x)
    ax1.set_xticklabels(index,rotation = 0,fontsize = 12)
    ax1.set_ylabel('IV(information value)',fontsize = 14)
    for a,b in zip(x,ivlist):
        plt.text(a,b+0.01,'%.4f'%b,ha = 'center',va = 'bottom',fontsize = 10)
    plt.savefig('iv取值.png', dpi = 300,bbox_inches = 'tight')
    plt.show()
    

    在这里插入图片描述
    四.模型训练阶段
    定义了get_woe函数,用于将原始数据转换为WoE值,以提高模型的训练结果。调用get_wor函数,将训练集和测试集属性转化为WoE值

    #模型训练阶段
    #求出属性的对应woe值
    def get_woe(feat,cut,woe):
        res = []
        for row in feat.iteritems():
            value = row[1]
            j = len(cut)-2
            m = len(cut)-2
            while j>=0:
                if value>=cut[j]:
                    j=-1
                else:
                    j-=1
                    m-=1
            res.append(woe[m])
        return res
    #调用get_woe函数,分别将训练集和测试集的属性值转为woe值
    woe_train = pd.DataFrame()
    woe_train['SeriousDlqin2yrs'] = train['SeriousDlqin2yrs']
    woe_train['RevolvingUtilizationOfUnsecuredLines'] = get_woe(train['RevolvingUtilizationOfUnsecuredLines'], cutx1, woex1)
    woe_train['age'] = get_woe(train['age'], cutx2, woex2)
    woe_train['NumberOfTime30-59DaysPastDueNotWorse'] = get_woe(train['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, woex3)
    woe_train['DebtRatio'] = get_woe(train['DebtRatio'], cutx4, woex4)
    woe_train['MonthlyIncome'] = get_woe(train['MonthlyIncome'], cutx5, woex5)
    woe_train['NumberOfOpenCreditLinesAndLoans'] = get_woe(train['NumberOfOpenCreditLinesAndLoans'], cutx6, woex6)
    woe_train['NumberOfTimes90DaysLate'] = get_woe(train['NumberOfTimes90DaysLate'], cutx7, woex7)
    woe_train['NumberRealEstateLoansOrLines'] = get_woe(train['NumberRealEstateLoansOrLines'], cutx8, woex8)
    woe_train['NumberOfTime60-89DaysPastDueNotWorse'] = get_woe(train['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, woex9)
    woe_train['NumberOfDependents'] = get_woe(train['NumberOfDependents'], cutx10, woex10)     
    
    #将测试集各属性替换成woe     
    woe_test = pd.DataFrame()
    woe_test['SeriousDlqin2yrs'] = train['SeriousDlqin2yrs']
    woe_test['RevolvingUtilizationOfUnsecuredLines'] = get_woe(train['RevolvingUtilizationOfUnsecuredLines'], cutx1, woex1)
    woe_test['age'] = get_woe(train['age'], cutx2, woex2)
    woe_test['NumberOfTime30-59DaysPastDueNotWorse'] = get_woe(train['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, woex3)
    woe_test['DebtRatio'] = get_woe(train['DebtRatio'], cutx4, woex4)
    woe_test['MonthlyIncome'] = get_woe(train['MonthlyIncome'], cutx5, woex5)
    woe_test['NumberOfOpenCreditLinesAndLoans'] = get_woe(train['NumberOfOpenCreditLinesAndLoans'], cutx6, woex6)
    woe_test['NumberOfTimes90DaysLate'] = get_woe(train['NumberOfTimes90DaysLate'], cutx7, woex7)
    woe_test['NumberRealEstateLoansOrLines'] = get_woe(train['NumberRealEstateLoansOrLines'], cutx8, woex8)
    woe_test['NumberOfTime60-89DaysPastDueNotWorse'] = get_woe(train['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, woex9)
    woe_test['NumberOfDependents'] = get_woe(train['NumberOfDependents'], cutx10, woex10)      
    
    
    import statsmodels.api as sm
    from sklearn.metrics import roc_curve,auc
    
    Y = woe_train['SeriousDlqin2yrs']
    X = woe_train.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome','NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis = 1)
    X1 = sm.add_constant(X)
    logit = sm.Logit(Y,X1)
    Logit_model = logit.fit()
    print('输出拟合的各项系数')
    print(Logit_model.params)
    

    在这里插入图片描述
    画出模型AUC曲线

    Y_test = woe_test['SeriousDlqin2yrs']
    X_test = woe_test.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome',
                            'NumberOfOpenCreditLinesAndLoans',
                            'NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1)
    X3 = sm.add_constant(X_test)
    resu = Logit_model.predict(X3)
    fpr,tpr,threshold = roc_curve(Y_test,resu)
    rocauc = auc(fpr,tpr)
    plt.plot(fpr,tpr,'y',label='AUC=%0.2f' % rocauc)
    plt.legend(loc='lower right')
    plt.plot([0,1],[0,1],'p--')
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.ylabel('TurePositive')
    plt.xlabel('FalsePositive')
    plt.savefig('模型AUC曲线.png',dpi=300,bbox_inches='tight')
    print('模型AUC曲线:')
    plt.show()
    
    

    在这里插入图片描述

    #定义get_score函数用于计算各个分箱的基础得分
    def get_score(coe,woe,factor):
        scores = []
        for w in woe:
            score = round(coe*w*factor,0)
            scores.append(score)
        return scores
    #定义compte_score函数,计算具体属性取值对应的基础得分
    def compute_score(feat,cut,score):
        res = []
        for row in feat.iteritems():
            value = row[1]
            j = len(cut)-2
            m = len(cut)-2
            while j>=0:
                if value>=cut[j]:
                    j=-1
                else:
                    j-=1
                    m-=1
            res.append(score[m])
        return res
    import math
    coe = Logit_model.params
    p = 20/math.log(2)
    q = 600-20*math.log(20)/math.log(2)
    baseScore = round(q+p*coe[0],0)
    
    x1 = get_score(coe[1],woex1,p)
    print('第1列属性取值在各分箱段对应的分数')
    print(x1)
    
    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)
    
    #print(x2)
    #print(x3)
    #print(x3)
    #计算分数
    test['BaseScore'] = np.zeros(len(test))+baseScore
    test['x1'] = compute_score(test['RevolvingUtilizationOfUnsecuredLines'],cutx1,x1)
    test['x2'] = compute_score(test['age'],cutx2,x2)
    test['x3'] = compute_score(test['NumberOfTime30-59DaysPastDueNotWorse'],cutx3,x3)
    test['x7'] = compute_score(test['NumberOfTimes90DaysLate'],cutx7,x7)
    test['x9'] = compute_score(test['NumberOfTime60-89DaysPastDueNotWorse'],cutx9,x9)
    
    test['Score'] = test['x1']+test['x2']+test['x3']+test['x7']+test['x9']+baseScore
    

    第1列属性取值在各分箱段对应的分数
    [20.0, 10.0, 4.0, -2.0, -7.0, -13.0, -19.0, -21.0, -41.0, -38.0]

    Normal = test.loc[test['SeriousDlqin2yrs']==1]
    Charged = test.loc[test['SeriousDlqin2yrs']==0]
    
    print('测试集中正常客户组信用评分统计描述')
    print(Normal['Score'].describe())
    print('测试集中违约客户组信用评分统计描述')
    print(Charged['Score'].describe())
    
    import seaborn as sns
    plt.figure(figsize = (10,4))
    sns.kdeplot(Normal['Score'],label = 'normal',linewidth = 2,linestyle = '--')
    sns.kdeplot(Charged['Score'],label = 'charged',linewidth = 2,linestyle = '-')
    plt.xlabel('Score',fontdict = {'size':10})
    plt.ylabel('probability',fontdict = {'size':10})
    plt.title('normal/charged',fontdict={'size':18})
    plt.savefig('违约与正常客户的信用分布情况.png',dpi = 300,bbox_inches = 'tight')
    plt.show()
    

    在这里插入图片描述

    违约客户与正常客户的信用分数分分布在这里插入图片描述

    将训练好的模型用于客户信用评分

    #将训练好的模型用于客户信用评分
    cusInfo = {'RevolvingUtilizationOfUnsecuredLines':0.248537,'age':48,'NumberOfTime30-59DaysPastDueNotWorse':0,
               'NumberOfTime60-89DaysPastDueNotWorse':0,'DebtRatio':0.177586,'MonthlyIncome':4166,
               'NumberOfOpenCreditLinesAndLoans':11,'NumberOfTimes90DaysLate':0,'NumberRealEstateLoansOrLines':1,
               'NumberOfTime60-89DaysPastDueNotWorse':0,'NumberOfDependents':0}
    custData = pd.DataFrame(cusInfo,pd.Index(range((1))))
    custData.drop(['DebtRatio','MonthlyIncome','NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis = 1)
    
    custData['x1'] = compute_score(custData['RevolvingUtilizationOfUnsecuredLines'], cutx1,x1)
    custData['x2'] = compute_score(custData['age'], cutx2,x2)
    custData['x3'] = compute_score(custData['NumberOfTime30-59DaysPastDueNotWorse'], cutx3,x3)
    custData['x7'] = compute_score(custData['NumberOfTimes90DaysLate'], cutx7,x7)
    custData['x9'] = compute_score(custData['NumberOfTime60-89DaysPastDueNotWorse'], cutx9,x9)
    
    custData['Score'] = custData['x1']+custData['x2']+custData['x3']+custData['x7']+custData['x9']+baseScore
    print('该客户的信用评分为:')
    print(custData.loc[0,'Score'])             
    

    该客户的信用评分为:
    613.0

    展开全文
  • 信用评分模型开发

    2020-06-18 11:06:15
    信用风险计量体系包括主体评级模型和债项评级两个部分。主体评级包含以下四个内容: 1.申请者评级 2.行为评级模型3.催收评级模型4.欺诈评级模型 数据来源: 本项目来源kaggle竞赛 Give Me Some Credit 2.1.1获取数据...

    一.背景:

    信用风险指的是交易对手未能履行约定合同中的义务造成经济损失的风险,即受信人不能履行还本付息的责任而使授信人的预期收益与实际收益发生偏离可能性,为金融风险的主要类型
    借贷的评分卡,是一种以分数的形式来衡量风险几率的一种手段,一般来说分数越高,风险越小
    信用风险计量体系包括主体评级模型和债项评级两个部分。主体评级包含以下四个内容:
    1.申请者评级 2.行为评级模型3.催收评级模型4.欺诈评级模型

    二. 数据来源:

    本项目来源kaggle竞赛 Give Me Some Credit
    2.1获取数据
    观察现有的数据和指标

    import numpy as np
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    data = pd.read_csv(r'E:/平时自学相关资料/CreditScoreModel-master/cs-training.csv')
    data.describe()
    

    在这里插入图片描述
    在这里插入图片描述
    2.2数据预处理
    2.2.1缺失值

    null=data.isnull().sum().sort_values(ascending=False)
    null_rate =data.isnull().sum().sort_values(ascending=False)/len(data)
    pd.concat([null,null_rate],axis=1)
    

    在这里插入图片描述
    缺失值的处理:
    ①缺失值极多:缺失样本占比极高,直接舍弃,作为特征加入反而会引入噪声
    ②非连续特征值缺失适中:将NaN作为一个新类别,加入到类别特征中
    ③连续值缺失适中:如果缺失样本适中,考虑给定一个step,然后离散化,将NaN作为一个type加入属性类目中
    ④缺失值较少:利用填充方法进行处理,均值,众数填充。RandomForest模型拟合数据,进行填充。要求有一定相关性。否则会引入噪声
    MonthIncome缺失19.8%和NumberofDependents 2.6%,对MonthIncome采用随机森林对数据插补,由于NumberofDependents缺失数据较少,可以直接删掉

    from sklearn.ensemble  import  RandomForestRegressor
    def set_missing(df):
        process_df = df.iloc[:,[6,1,2,3,4,5,7,8,9,10]]
        known = process_df[process_df.MonthlyIncome.notnull()].values
        unknown = process_df[process_df.MonthlyIncome.isnull()].values
        X = known[:, 1:]
        y = known[:, 0]
        rfr = RandomForestRegressor(random_state=0, n_estimators=200,max_depth=3,n_jobs=-1)
        rfr.fit(X,y)
        predicted = rfr.predict(unknown[:, 1:]).round(0)
        print(predicted)
        df.loc[(df.MonthlyIncome.isnull()), 'MonthlyIncome'] = predicted
        return df
    
    data=set_missing(data)
    data=data.dropna()
    data = data.drop_duplicates()
    

    2.2.2 异常值
    age

    plt.boxplot(x=data.age)
    plt.xlabel('age')
    plt.title('Age')
    plt.show()
    

    在这里插入图片描述
    由箱线图可知,年龄小于等于0为异常值,需要删除

    RevolvingUtilizationOfUnsecuredLines(可用额度比值)及DebtRatio(负债率)

    fig =plt.figure(figsize=(6,6))
    ax =fig.add_subplot()
    ax.boxplot([data.RevolvingUtilizationOfUnsecuredLines,data.DebtRatio])
    ax.set_xticklabels(['RevolvingUtilizationOfUnsecuredLines','DebtRatio'])
    plt.title('UnsecuredLines and DebtRatio')
    plt.show()
    

    在这里插入图片描述
    (NumberOfTime30-59DaysPastDueNotWorse)逾期30天数;(NumberOfTimes90DaysLate)逾期90天数;(NumberOfTime60-89DaysPastDueNotWorse)逾期60天数

    fig =plt.figure(figsize=(6,6))
    ax =fig.add_subplot()
    ax.boxplot([data['NumberOfTime30-59DaysPastDueNotWorse'],data['NumberOfTimes90DaysLate'],data['NumberOfTime60-89DaysPastDueNotWorse']])
    ax.set_xticklabels(['30-90','90','60-89'])
    plt.title('PastDueNotWorse')
    plt.grid()
    plt.show()
    

    在这里插入图片描述
    由图可知,均存在两个异常点,需要删除

    data=data[data['age']>0]
    data = data[data['NumberOfTime30-59DaysPastDueNotWorse'] < 90]
    

    2.2.3 单变量分析
    好坏客户的比值

    data.SeriousDlqin2yrs.value_counts(normalize=True).plot.bar()
    print("坏客户的比例%s"%[data.SeriousDlqin2yrs.value_counts(normalize=True)[1]/data.SeriousDlqin2yrs.value_counts(normalize=True)[0]])
    plt.show()
    

    在这里插入图片描述
    2.2.4多变量的分析

    fig = plt.figure(figsize=(7,6))
    ax=sns.heatmap(data.corr(),annot=True,fmt='.2f')
    bottom,top =ax.get_ylim()
    ax.set_ylim()
    ax.set_ylim(bottom+0.5,top-0.5)
    plt.show()
    

    在这里插入图片描述
    由上图看出,各变量之间的相关性很小,不存在共线性可能

    三.特征工程

    特征选择非常重要,好的特征能够构造出好的模型,通过Python来实现,这里采用信用卡评分模型常用的IV值筛选。具体的IV值及WOE计算方法后面解释。
    3.1 特征分箱
    特征分箱指的是将连续变量离散化或将多状态的离散变量合并成少状态。离散特征的增加和减少都容易,易于模型的快速迭代,离散后的特征对异常数据有很强的鲁棒性,能够减少未离散化之前异常值对模型的干扰,离散化后可以进行特征交叉。本文的模型为逻辑回归,逻辑回归为广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独权重,相当于为模型引入非线性,提升模型表达能力,加大拟合,同时降低了过拟合风险
    特征分箱常用的有以下几种方法:有监督的Best-KS,ChiMerge,无监督的包括等频,等距,聚类。根据数据特征采用不同的分箱方式。这里采用聚类,等距,代码如下

    from sklearn.model_selection import train_test_split
    Y=data['SeriousDlqin2yrs']
    X=data.iloc[:,1:]
    X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.3,random_state=1)
    train = pd.concat([Y_train,X_train],axis=1)
    test = pd.concat([Y_test,X_test],axis=1)
    train.to_csv('TrainData.csv',index=False)
    test.to_csv('TestData.csv',index=False)
    

    将数据分为训练集和测试集,便于后续验证,数据分箱代码如下:

    #聚类分箱
    from scipy.stats import spearmanr
    def best_cut(X,Y,n):
        r= 0
        cutx =[]
        while abs(r)<1:
            d1= pd.DataFrame({'X':X,'Y':Y})
            cut= pd.qcut(X,n)
            d2= d1.groupby(cut)
            r,q = spearmanr(d2.mean().X,d2.mean().Y)
            n = n-1
        cutx.append(float('-inf'))
        for i in range(1,n+1):
            qua= X.quantile(i/(n+1))
            cutx.append(qua)
        cutx.append(float('inf'))    
        return cut,cutx
    
    train_data =pd.read_csv('TrainData.csv')
    cut1,cutx1=best_cut(train_data.RevolvingUtilizationOfUnsecuredLines,train_data.SeriousDlqin2yrs,10)
    cut2,cutx2= best_cut(train_data.age,train_data.SeriousDlqin2yrs,10)
    cut4,cutx4=best_cut(train_data.DebtRatio,train_data.SeriousDlqin2yrs,10)
    cut5,cutx5=best_cut(train_data.MonthlyIncome,train_data.SeriousDlqin2yrs,10)
    

    将可用额度比值,年龄,负债率,月收入进行聚类分箱,其余进行连续变量的离散化

    pinf =float('inf')
    ninf= float('-inf')
    cutx3 = [ninf, 0, 1, 3, 5, pinf]
    cutx6 = [ninf, 1, 2, 3, 5, pinf]
    cutx7 = [ninf, 0, 1, 3, 5, pinf]
    cutx8 = [ninf, 0,1,2, 3, pinf]
    cutx9 = [ninf, 0, 1, 3, pinf]
    cutx10 = [ninf, 0, 1, 2, 3, 5, pinf]
    cut3=pd.cut(train_data["NumberOfTime30-59DaysPastDueNotWorse"],cutx3,labels=False)
    cut6=pd.cut(train_data["NumberOfOpenCreditLinesAndLoans"],cutx6,labels=False)
    cut7=pd.cut(train_data["NumberOfTimes90DaysLate"],cutx7,labels=False)
    cut8=pd.cut(train_data["NumberRealEstateLoansOrLines"],cutx8,labels=False)
    cut9=pd.cut(train_data["NumberOfTime60-89DaysPastDueNotWorse"],cutx9,labels=False)
    cut10=pd.cut(train_data["NumberOfDependents"],cutx10,labels=False)
    

    3.2 计算WOE(weight of evidence)
    WOE的全称是“Weight of Evidence”,及证据权重,WOE是对原始自变量的一种编码形式 ,要对一个变量进行WOE编码,需要首先对这个变量进行 分组处理(也叫离散化、分箱等)分组后,对于第i组,WOE的计算公式如下:
    在这里插入图片描述
    pyi:这组中响应客户(风险模型中,对应的是违约客户,总之,指的是模型中预测变量取值为“是”或者1的个体)占所有样本中所有响应客户的比例

    pni: 这组中未响应客户占样本中所有未响应客户的比例
    yi:这个组中响应客户的数量
    ni:这个组中未响应客户的数量
    yT:是样本中所有响应的数量
    nT:样本中所有未响应的数量

    从上述公式中看出,WOE表示的实际上是“ 当前分组中响应客户占所有响应客户的比例”和“ 当前分组中没有响应的客户占所有没有响应的客户的比例”的差异
    WOE越大,这种差异越大,这个分组里样本响应可能性就越大,WOE越小,差异越小。计算WOE代码

    def cal_woe(df,cut):
        bad_sum = df.SeriousDlqin2yrs.sum()
        good_sum = df.SeriousDlqin2yrs.count()-bad_sum
        group = df.groupby(cut)['SeriousDlqin2yrs']
        cut_bad =group.sum()
        cut_good =group.count()-cut_bad
        woe= np.log((cut_bad/bad_sum)/(cut_good/good_sum))
        return woe
    

    3.3 IV的概念
    IV全称是information Value,中文是信息价值,或者信息量,IV这一指标就是用来衡量自变量预测能力(衡量自变量对目标变量影响程度的指标),类似的指标还有信息增益,基尼系数等。
    假设在一个分类问题中,目标变量的类别有两类:Y1,Y2。对于一个待预测的个体A,要判断A属于Y1还是Y2,需要一定的信息,假定信息总量是I,而这些信息蕴含在自变量C1,C2,C3…,Cn中,那么对于其中的一个变量Ci来说,其蕴含的信息越多,那么它对于判断A属于Y1还是Y2的贡献就越大,Ci的信息价值就越大,Ci的IV就越大,它就越应该进入到入模变量

    3.4 IV的计算
    在这里插入图片描述
    有了一个变量各分组的iv值,我们就可以计算整个变量的iv值,方法很简单,就是把各分组的IV相加:
    在这里插入图片描述
    其中,n为变量分组个数(即分箱后有多少组)

    def get_iv(df,cut,cutwoe):
        bad_attribute = df.groupby(cut).sum().SeriousDlqin2yrs/df.SeriousDlqin2yrs.sum() 
        good_attribute =(df.groupby(cut).count().SeriousDlqin2yrs-df.groupby(cut).sum().SeriousDlqin2yrs)/(df.SeriousDlqin2yrs.count()-df.SeriousDlqin2yrs.sum())
        iv= (bad_attribute-good_attribute)*cutwoe
        return np.sum(iv)
    
    cut1_iv=get_iv(train_data,cut1,cut1_woe)
    cut2_iv=get_iv(train_data,cut2,cut2_woe)
    cut3_iv=get_iv(train_data,cut3,cut3_woe)
    cut4_iv=get_iv(train_data,cut4,cut4_woe)
    cut5_iv=get_iv(train_data,cut5,cut5_woe)
    cut6_iv=get_iv(train_data,cut6,cut6_woe)
    cut7_iv=get_iv(train_data,cut7,cut7_woe)
    cut8_iv=get_iv(train_data,cut8,cut8_woe)
    cut9_iv=get_iv(train_data,cut9,cut9_woe)
    cut10_iv=get_iv(train_data,cut10,cut10_woe)
    cut_iv=pd.DataFrame([cut1_iv,cut2_iv,cut3_iv,cut4_iv,cut5_iv,cut6_iv,cut7_iv,cut8_iv,cut9_iv,cut10_iv],columns=['IV'])
    
    cut_iv.plot.bar(figsize=(8,6))
    iv_list=[cut1_iv,cut2_iv,cut3_iv,cut4_iv,cut5_iv,cut6_iv,cut7_iv,cut8_iv,cut9_iv,cut10_iv]
    for a,b in zip(np.arange(10),iv_list):
        plt.text(a,b+0.01,'%.3f'%b,ha='center',va='bottom',fontsize=10)
    plt.show()
    

    在这里插入图片描述
    IV值大小的判断,过高的IV可能会有潜在的风险,只能用于二分类的目标变量,IV小于0.02 没有预测性 不用;IV 0.02 to 0.1 弱预测;IV 0.1 to 0.2 一定预测;IV 0.2+ 高预测;将IV值小于0.2的变量删除。

    train_data.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1,inplace=True)
    test= pd.read_csv('TestData.csv')
    test.drop(['SeriousDlqin2yrs','DebtRatio','MonthlyIncome', 'NumberOfOpenCreditLinesAndLoans','NumberRealEstateLoansOrLines','NumberOfDependents'],axis=1,inplace=True)
    

    3.5 WOE值替换
    目的是减少逻辑回归的自变量处理量

    def repalce_woe(series,cutx,woe):
        i=0
        list1=[]
        while i<len(series):
            value = series[i]
            m = len(cutx)-2
            n = len(cutx)-2
            while m>=0:
                if cutx[m]<=value:
                    m=m-1
                else:
                    m=m-1
                    n=n-1
            list1.append(woe[n])
            i=i+1
        return list1   
    
    train_data['RevolvingUtilizationOfUnsecuredLines'] = replace_woe(train_data['RevolvingUtilizationOfUnsecuredLines'].values, cutx1, woex1)
    train_data['age'] = Series(replace_woe(train_data['age'].values, cutx2, woex2))
    train_data['NumberOfTime30-59DaysPastDueNotWorse'] = replace_woe(train_data['NumberOfTime30-59DaysPastDueNotWorse'].values, cutx3, woex3)
    train_data['NumberOfTimes90DaysLate'] = replace_woe(train_data['NumberOfTimes90DaysLate'].values, cutx7, woex7)
    train_data['NumberOfTime60-89DaysPastDueNotWorse'] = replace_woe(train_data['NumberOfTime60-89DaysPastDueNotWorse'].values, cutx9, woex9)
    train_data.to_csv('WoeData.csv', index=False)
    
    test_data= pd.read_csv('TestData.csv')
    test_data['RevolvingUtilizationOfUnsecuredLines'] = replace_woe(test_data['RevolvingUtilizationOfUnsecuredLines'].values, cutx1, woex1)
    test_data['age'] = replace_woe(test_data['age'].values, cutx2, woex2)
    test_data['NumberOfTime30-59DaysPastDueNotWorse'] = replace_woe(test_data['NumberOfTime30-59DaysPastDueNotWorse'].values, cutx3, woex3)
    test_data['NumberOfTimes90DaysLate'] = replace_woe(test_data['NumberOfTimes90DaysLate'].values, cutx7, woex7)
    test_data['NumberOfTime60-89DaysPastDueNotWorse'] =replace_woe(test_data['NumberOfTime60-89DaysPastDueNotWorse'].values, cutx9, woex9)
    test_data.to_csv('TestWoeData.csv',index=False)
    

    四.逻辑回归模型

    from sklearn.linear_model import LogisticRegression
    data = pd.read_csv('WoeData.csv')
    Y=data['SeriousDlqin2yrs']
    X=data.iloc[:,1:]
    log= LogisticRegression(solver='lbfgs')
    log.fit(X,Y)
    test = pd.read_csv('TestWoeData.csv')
    Y_test = test['SeriousDlqin2yrs']
    X_test = test.iloc[:,1:]
    Y_pre1=log.decision_function(X_test)
    

    通过auc和roc_curve 来判断模型好坏

    from sklearn.metrics import roc_curve, auc
    plt.rcParams['font.sans-serif']=['SimHei']
    fpr,tpr,threshold = roc_curve(Y_test,Y_pre1)
    rocauc = auc(fpr, tpr)
    plt.plot(fpr, tpr, label='AUC = %0.2f' % rocauc)
    plt.legend(loc='best')
    plt.plot([0, 1], [0, 1], 'r--')
    plt.xlim([0, 1])
    plt.ylim([0, 1])
    plt.ylabel(r'真正率')
    plt.xlabel(r'假正率')
    plt.show()
    

    在这里插入图片描述
    AUC值为0.85,说明该模型的预测效果还是不错的,正确率较高。

    五. 信用评分模型

    说明
    由逻辑回归的基本原理,我们将客户违约的概率表示为p,则正常的概率为1-p。因此,可以得到:
    在这里插入图片描述
    此时,客户违约的概率p可表示为:
    在这里插入图片描述
    评分卡设定的分值刻度可以通过将分值表示为比率对数的线性表达式来定义,即可表示为下式:
    在这里插入图片描述
    其中,A和B是常数,式中的负号可以使得违约概率越低,得分越高。通常情况下,这是分值的理想变动方向,即高分值代表低风险,低分值代表高风险。逻辑回归模型计算比率如下所示:
    在这里插入图片描述
    其中,用建模参数拟合模型可以得到模型参数β0 ,β1…βn.
    常数A,B值可以通过将两个已知或假设的分值带入到计算得到,通常情况下,需要设定两个假设:
    1.给某个特定的比率设定特定的预期分值
    2.确定比率翻番的分数(PDO)
    假设设定评分卡刻度使得比率为{1:20}(违约正常比)时的分值为600分,PDO为20分,代入式中求得:
    在这里插入图片描述
    评分卡刻度参数A和B确定以后,就可以计算比率和违约概率,以及对应的分值,通常将A称为补偿,常数B称为刻度。
    则评分卡的分值可表达为:
    在这里插入图片描述
    式中:变量x 1 …x n是出现在最终模型中的自变量,即为入模指标。由于此时所有变量都用WOE转换进行了转换,可以将这些自变量中的每一个都写(β i ω ij )δ ij 的形式
    在这里插入图片描述
    式中ω ij 为第i行第j个变量的WOE,为已知变量;β i 为逻辑回归方程中的系数,为已知变量;δ ij 为二元变量,表示变量i是否取第j个值。上式可重新表示为:
    在这里插入图片描述
    此式即为最终评分卡公式。如果x 1 …x n变量取不同行并计算其WOE值,式中表示的标准评分卡格式,如表3.20所示
    在这里插入图片描述
    5.1 建立信用评分
    这里初始评分设定为600,违约率初始为1:20,当违约上升1倍时,PDO变化为20,则可以进行计算

    def get_score(woe,coe,factor):
        scores=[]
        for w in woe:
            score=-round(w*coe*factor,0)
            scores.append(score)
        return scores
    
    def compute_score(series,cut,score):
        list1 = []
        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
            list1.append(score[m])
            i += 1
        return list1
    
    log.coef_
    log.intercept_
    

    在这里插入图片描述
    在这里插入图片描述

    coe=[0.65211317,0.49102952,1.0209049,1.7698133,1.04021588]
    B= 20/np.log(2)
    A= 600 + B*np.log(120)
    base_point = round(A- B*(log.intercept_),0)
    # 各项部分分数
    x1 = get_score(cut1_woe,coe[0],B) #'RevolvingUtilizationOfUnsecuredLines'
    x2 = get_score(cut2_woe,coe[1],B)
    #'age'
    x3 = get_score(cut3_woe,coe[2],B)
    #'NumberOfTime30-59DaysPastDueNotWorse'
    x7 = get_score(cut7_woe,coe[3],B)
    #'NumberOfTimes90DaysLate'
    x9 = get_score(cut9_woe,coe[4],B)
    #'NumberOfTime60-89DaysPastDueNotWorse'
    print(x1,x2, x3, x7, x9)
    

    在这里插入图片描述
    不同变量,不同区间的得分如上图所示,在测试集进行总得分的计算,如下

    test1 = pd.read_csv('TestData.csv')
    test1['BaseScore']=np.zeros(len(test1))+baseScore
    test1['x1'] = compute_score(test1['RevolvingUtilizationOfUnsecuredLines'], cutx1, x1)
    test1['x2'] = compute_score(test1['age'], cutx2, x2)
    test1['x3'] = compute_score(test1['NumberOfTime30-59DaysPastDueNotWorse'], cutx3, x3)
    test1['x7'] = compute_score(test1['NumberOfTimes90DaysLate'], cutx7, x7)
    test1['x9'] = compute_score(test1['NumberOfTime60-89DaysPastDueNotWorse'], cutx9, x9)
    test1['Score'] = test1['x1'] + test1['x2'] + test1['x3'] + test1['x7'] +test1['x9']  + baseScore
    
    这样完成了整个评分卡的建立,分数越高,违约的风险越低。反之,风险越高。
    
    
    展开全文
  • 不同机构的信用评分模型不尽相同,主要有两类: 金融机构: (1)申请风险评分 (2)行为风险评分/行为收益评分/行为流失倾向评分 (3)申请欺诈评分/交易欺诈评分 征信局: (1)征信局风险/破产/收益评分 (2)市场反应...

    不同机构的信用评分模型不尽相同,主要有两类:

    金融机构:

    (1)申请风险评分

    (2)行为风险评分/行为收益评分/行为流失倾向评分

    (3)申请欺诈评分/交易欺诈评分

    征信局:

    (1)征信局风险/破产/收益评分

    (2)市场反应评分

    (3)转账倾向评分

    评分卡开发流程:

    (1)数据准备:

     

    特征衍生/数据整合/WOE/单变量统计

    (2)变量选择

    变量粗筛:iv/缺失率/单类别比例

    模型细筛:lasso/step

    (3)模型开发

    logistic

    (4)模型验证

    准确性/稳健性/有意义

    (5)评分卡刻度与实施

     

    微信公众号:Data Analyst

     

     

    展开全文
  • 信用标准评分卡模型开发及实现

    万次阅读 多人点赞 2017-08-03 02:07:58
    一、信用风险评级模型的类型信用风险计量体系包括主体评级模型和债项评级两部分。主体评级和债项评级均有一系列评级模型组成,其中主体评级模型可用“四张卡”来表示,分别是A卡、B卡、C卡和F卡;债项评级模型通常...
  • 确立Y值:消费贷信用评分模型一般以历史M3+为坏客户定义标准,作为正类,用1表示,历史未逾期的好客户为负类,用0表示,其他有逾期但未进入M3+的客户作为灰客户,用0.5表示,统计分布,但不作为建模样本。...
  • 银行和信用卡公司等贷方使用信用评分来评估向消费者放贷所带来的潜在风险,并减轻坏账造成的损失。 贷方使用信用评分来确定谁有资格获得贷款、利率是多少以及信用额度是多少。 贷方还使用信用评分来确定哪些客户可能...
  • 全面的信贷评分模型开发流程介绍
  • 数据挖掘技术在信用信用风险评估中的应用_刘武男.caj

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,535
精华内容 2,214
关键字:

信用评分开发