风控模型评估

  本文总结了一下评分卡建模过程中常用的模型评估方法,并结合代码展示,理论结合实际,方便初学者对模型评估的方法有深入的理解。之前写过一篇模型评估的指标,偏于理论,详情见风控模型指标详解

1.AUC

  AUC值指的是ROC曲线下面积大小,该值能够量化反映基于ROC曲线衡量的模型性能。所以,需要了解ROC曲线的绘制方法。
  首先,需要了解TPR(真阳性率)和FPR(假阳性率)。TPR就是P个正样本中被预测为正的概率,FPR是N个负样本中被预测为正样本的概率。(FPR,TPR)形成ROC曲线上的一个点。

  ROC曲线通过不断移动截断点来生成不同的(FPR,TPR),可以理解为评分卡中的cut-off在不断变化。

  绘制出ROC曲线之后,AUC就是ROC曲线下的面积。此外ROC曲线相对应的P-R曲线之间的区别,有兴趣的可以研究下,这里不再赘述。下面附上代码:

def plot_roc(y_label,y_pred):
    """
    y_label:测试集的y
    y_pred:对测试集预测后的概率
    
    return:ROC曲线
    """
    tpr,fpr,threshold = metrics.roc_curve(y_label,y_pred) 
    AUC = metrics.roc_auc_score(y_label,y_pred) 
    fig = plt.figure(figsize=(6,4))
    ax = fig.add_subplot(1,1,1)
    ax.plot(tpr,fpr,color='blue',label='AUC=%.3f'%AUC) 
    ax.plot([0,1],[0,1],'r--')
    ax.set_ylim(0,1)
    ax.set_xlim(0,1)
    ax.set_title('ROC')
    ax.legend(loc='best')
    return plt.show(ax)

2.KS

  KS曲线与ROC曲线非常的类似。KS曲线是两条线,其横轴是阈值,纵轴是TPR与FPR。两条曲线之间之间相距最远的地方对应的阈值,就是最能划分模型的阈值。KS曲线是用来衡量分类型模型准确度的工具。

KS的计算步骤如下:

  1. 计算每个评分区间的好坏账户数。
  2. 计算每个评分区间的累计好账户数占总好账户数比率(good%)和累计坏账户数占总坏账户数比率(bad%)。
  3. 计算每个评分区间累计坏账户占比与累计好账户占比差的绝对值(累计good%-累计bad%),然后对这些绝对值取最大值即得此评分卡的K-S值。
def plot_model_ks(y_label,y_pred):
    """
    y_label:测试集的y
    y_pred:对测试集预测后的概率
    
    return:KS曲线
    """
    pred_list = list(y_pred) 
    label_list = list(y_label)
    total_bad = sum(label_list)
    total_good = len(label_list)-total_bad 
    items = sorted(zip(pred_list,label_list),key=lambda x:x[0]) 
    step = (max(pred_list)-min(pred_list))/200 
    
    pred_bin=[]
    good_rate=[] 
    bad_rate=[] 
    ks_list = [] 
    for i in range(1,201): 
        idx = min(pred_list)+i*step 
        pred_bin.append(idx) 
        label_bin = [x[1] for x in items if x[0]<idx] 
        bad_num = sum(label_bin)
        good_num = len(label_bin)-bad_num  
        goodrate = good_num/total_good 
        badrate = bad_num/total_bad
        ks = abs(goodrate-badrate) 
        good_rate.append(goodrate)
        bad_rate.append(badrate)
        ks_list.append(ks)
    
    fig = plt.figure(figsize=(8,6))
    ax = fig.add_subplot(1,1,1)
    ax.plot(pred_bin,good_rate,color='green',label='good_rate')
    ax.plot(pred_bin,bad_rate,color='red',label='bad_rate')
    ax.plot(pred_bin,ks_list,color='blue',label='good-bad')
    ax.set_title('KS:{:.3f}'.format(max(ks_list)))
    ax.legend(loc='best')
    return plt.show(ax)

  此外还有基尼系数,列出三者的综合判断标准:

3.交叉验证

  交叉验证是为了评估模型的泛化能力。

  1. k折交叉验证
  • 第一步,不重复抽样将原始数据随机分为 k 份。
  • 第二步,每一次挑选其中 1 份作为测试集,剩余 k-1 份作为训练集用于模型训练。
  • 第三步,重复第二步 k 次,这样每个子集都有一次机会作为测试集,其余子集作为训练集。在每个训练集上训练后得到一个模型,用这个模型在相应的测试集上测试,计算并保存模型的评估指标。
  • 第四步,计算 k 组测试结果的平均值作为模型精度的估计,并作为当前 k 折交叉验证下模型的性能指标
  1. 时间序列交叉验证
      金融数据具有时间周期性的特点,不同时间段的样本分布和变量分布会有一定差异,首先在选取建模的样本时就要考虑是否能代表总体的样本分布或者近段时间用户的状态。在做交叉验证时也需要考虑到时间周期这一点,例如我们选取的是1月份至10月份的数据,可以借鉴K折验证的思想,将数据集按照月份分为 10份,每次挑选其中一份作为测试集,其他作为训练集,得到10组的验证结果,观察随着月份的推移,模型的结果是否有比较大的趋势变化,这个也可以反映出样本是否稳定。如果变化较明显,则需要分析是什么原因导致的,是内部大的业务政策,还是外部的经济环境。
# 交叉验证
def cross_verify(x,y,estimators,fold,scoring='roc_auc'):
    """
    x:自变量的数据集
    y:target的数据集
    estimators:验证的模型
    fold:交叉验证的策略
    scoring:评级指标,默认auc
    
    return:交叉验证的结果
    """
    cv_result = cross_val_score(estimator=estimators,X=x,y=y,cv=fold,n_jobs=-1,scoring=scoring)
    print('CV的最大AUC为:{}'.format(cv_result.max()))
    print('CV的最小AUC为:{}'.format(cv_result.min()))
    print('CV的平均AUC为:{}'.format(cv_result.mean()))
    plt.figure(figsize=(6,4))
    plt.title('交叉验证的评价指标分布图')
    plt.boxplot(cv_result,patch_artist=True,showmeans=True,
            boxprops={'color':'black','facecolor':'yellow'},
            meanprops={'marker':'D','markerfacecolor':'tomato'},
            flierprops={'marker':'o','markerfacecolor':'red','color':'black'},
            medianprops={'linestyle':'--','color':'orange'})
    return plt.show()

画出的效果图如下:

4.学习曲线

  学习曲线的纵轴是训练集的大小,横轴是模型在训练集上和交叉验证集上的平均得分(准确率),可以反映随着训练集大小的改变,模型在训练集和验证集上的误差得分情况。进而判定模型的拟合情况。

  • 第一张图中,随着训练集不断增大,模型在训练集和验证集上的得分不断靠近,但两者的得分都比较低,存在欠拟合的问题。
  • 第二张图中,随着训练集增大,模型在训练集和验证集上的得分不断靠近,且两者的得分都比较高,说明模型的拟合比较良好。
    更多关于学习曲线的问题可以查看官方文档,链接是学习曲线
    注意:金融模型很容易出现过拟合的问题,解决过拟合的方法有很多,例如增加建模样本,正则化等,例如逻辑回归里可以选择L1正则化或L2正则化,且可设置正则化的强度,另外做评分卡时,入模的变量不宜太多,太多的变量会使模型过于复杂,容易出现过拟合,一般应限制在15个以下。
# 学习曲线
def plot_learning_curve(estimator,x,y,cv=None,train_size = np.linspace(0.1,1.0,5),plt_size =None):
    """
    estimator :画学习曲线的基模型
    x:自变量的数据集
    y:target的数据集
    cv:交叉验证的策略
    train_size:训练集划分的策略
    plt_size:画图尺寸
    
    return:学习曲线
    """
    from sklearn.model_selection import learning_curve
    train_sizes,train_scores,test_scores = learning_curve(estimator=estimator,
                                                          X=x,
                                                          y=y,
                                                          cv=cv,
                                                          n_jobs=-1,
                                                          train_sizes=train_size)
    train_scores_mean = np.mean(train_scores,axis=1)
    train_scores_std = np.std(train_scores,axis=1)
    test_scores_mean = np.mean(test_scores,axis=1)
    test_scores_std = np.std(test_scores,axis=1)
    plt.figure(figsize=plt_size)
    plt.xlabel('Training-example')
    plt.ylabel('score')
    plt.fill_between(train_sizes,train_scores_mean-train_scores_std,
                     train_scores_mean+train_scores_std,alpha=0.1,color='r')
    plt.fill_between(train_sizes,test_scores_mean-test_scores_std,
                     test_scores_mean+test_scores_std,alpha=0.1,color='g')
    plt.plot(train_sizes,train_scores_mean,'o-',color='r',label='Training-score')
    plt.plot(train_sizes,test_scores_mean,'o-',color='g',label='cross-val-score')
    plt.legend(loc='best')
    return plt.show()

5.混淆矩阵

  混淆矩阵的指标有精确率,查全率(召回率),误伤率。这三个指标的值取决于评分卡的cutoff点怎么设置。评分卡最后会输出一个评分分布表,根据评分的等级和业务目标来选择适当的cutoff点,从而计算出这三个指标。

# 混淆矩阵 /分类报告
def plot_matrix_report(y_label,y_pred): 
    """
    y_label:测试集的y
    y_pred:对测试集预测后的概率
    
    return:混淆矩阵
    """
    matrix_array = metrics.confusion_matrix(y_label,y_pred)
    plt.matshow(matrix_array, cmap=plt.cm.summer_r)
    plt.colorbar()

    for x in range(len(matrix_array)): 
        for y in range(len(matrix_array)):
            plt.annotate(matrix_array[x,y], xy =(x,y), ha='center',va='center')

    plt.xlabel('True label')
    plt.ylabel('Predict label')
    print(metrics.classification_report(y_label,y_pred))
    return plt.show()

【作者】:Labryant
【原创公众号】:风控猎人
【简介】:某创业公司策略分析师,积极上进,努力提升。乾坤未定,你我都是黑马。
【转载说明】:转载请说明出处,谢谢合作!~

猜你喜欢

转载自blog.csdn.net/lc434699300/article/details/105102696