逻辑回归评分卡实现和评估

上一节讲得是模型评估,主要有ROC曲线、KS曲线、学习曲线和混淆矩阵。今天学习如何实现评分卡和对评分卡进行评估。

  首先,要了解评分卡是如何从概率映射到评分的,这个之前写过评分卡映射的逻辑。一定要看,明白概率如何映射到评分的以及每个变量的得分如何计算。附上评分卡映射的代码。结合逻辑回归评分卡映射的原理才能看懂代码。

from sklearn.linear_model import LogisticRegression'''第六步:逻辑回归模型。要求:1,变量显著2,符号为负'''y = trainData['y']x = trainData[multi_analysis]lr_model = LogisticRegression(C=0.1)lr_model.fit(x,y)trainData['prob'] = lr_model.predict_proba(x)[:,1]# 评分卡刻度def cal_scale(score,odds,PDO,model):    """    odds:设定的坏好比    score:在这个odds下的分数    PDO: 好坏翻倍比    model:逻辑回归模型        return :A,B,base_score    """    B = PDO/np.log(2)    A = score+B*np.log(odds)    # base_score = A+B*model.intercept_[0]    print('B: {:.2f}'.format(B))    print('A: {:.2f}'.format(A))    # print('基础分为:{:.2f}'.format(base_score))    return A,B    #假设基础分为50,odds为5%,PDO为10,可以自行调整。这一步是为了计算出A和B。cal_scale(50,0.05,10,lr_model)def Prob2Score(prob, A,B):    #将概率转化成分数且为正整数    y = np.log(prob/(1-prob))    return float(A-B*y)trainData['score'] = trainData['prob'].map(lambda x:Prob2Score(x, 6.78,14.43))

  可以看到,评分越高,违约概率越低。网上很多实现评分卡映射的代码,都没太看懂,这个是根据逻辑来写的,有时间再把映射逻辑整理一下。

1. 得分的KS曲线

  和模型的KS曲线一样,只不过横坐标的概率变成了得分。直接放上代码。

# 得分的KSdef plot_score_ks(df,score_col,target):    """    df:数据集    target:目标变量的字段名    score_col:最终得分的字段名    """    total_bad = df[target].sum()    total_good = df[target].count()-total_bad    score_list = list(df[score_col])    target_list = list(df[target])    items = sorted(zip(score_list,target_list),key=lambda x:x[0])    step = (max(score_list)-min(score_list))/200         score_bin=[]    good_rate=[]    bad_rate=[]    ks_list = []    for i in range(1,201):        idx = min(score_list)+i*step        score_bin.append(idx)        target_bin = [x[1] for x in items if x[0]

2. PR曲线

  还是这个混淆矩阵的图,P是查准率、精确率,R是查全率、召回率。这两个指标时既矛盾又统一的。因为为了提高精确率P,就是要更准确地预测正样本,但此时往往会过于保守而漏掉很多没那么有把握的正样本,导致召回率R降低。
  同ROC曲线的形成一样,PR曲线的形成也是不断移动截断点形成不同的(R,P)绘制成一条线。

  当接近原点时,召回率R接近于0,精确率P较高,说明得分前几位的都是正样本。随着召回率的增加,精确率整体下降,当召回率为1时,说明所有的正样本都被挑了出来,此时的精确率很低,其实就是相当于你将大部分的样本都预测为正样本。注意,只用某个点对应的(R,P)无法全面衡量模型的性能,必须要通过PR曲线的整体表现。此外,还有F1 score和ROC曲线也能反映一个排序模型的性能。

  • PR曲线和ROC曲线的区别
      当正负样本的分布发生变化时,ROC曲线的形状基本不变,PR曲线形状会发生剧烈变化。上图中PR曲线整体较低就是因为正负样本不均衡导致的。因为比如评分卡中坏客户只有1%,好客户有99%,将全部客户预测为好客户,那么准确率依然有99%。虽然模型整体的准确率很高,但并不代表对坏客户的分类准确率也高,这里坏客户的分类准确率为0,召回率也为0。
# PR曲线def plot_PR(df,score_col,target,plt_size=None):    """    df:得分的数据集    score_col:分数的字段名    target:目标变量的字段名    plt_size:绘图尺寸        return: PR曲线    """    total_bad = df[target].sum()    score_list = list(df[score_col])    target_list = list(df[target])    score_unique_list = sorted(set(list(df[score_col])))    items = sorted(zip(score_list,target_list),key=lambda x:x[0])    precison_list = []    tpr_list = []    for score in score_unique_list:        target_bin = [x[1] for x in items if x[0]<=score]        bad_num = sum(target_bin)        total_num = len(target_bin)        precison = bad_num/total_num        tpr = bad_num/total_bad        precison_list.append(precison)        tpr_list.append(tpr)        plt.figure(figsize=plt_size)    plt.title('PR曲线')    plt.xlabel('查全率')    plt.ylabel('精确率')    plt.plot(tpr_list,precison_list,color='tomato',label='PR曲线')    plt.legend(loc='best')    return plt.show()

3.得分分布图

  理想中最好的评分卡模型应该是将好坏客户完全区分出来,但是实际中好坏用户的评分会有一定的重叠,我们要做的尽量减小重叠。
  另外好坏用户的得分分布最好都是正态分布,如果呈双峰或多峰分布,那么很有可能是某个变量的得分过高导致,这样对评分卡的稳定性会有影响。

# 得分分布图def plot_score_hist(df,target,score_col,plt_size=None,cutoff=None):    """    df:数据集    target:目标变量的字段名    score_col:最终得分的字段名    plt_size:图纸尺寸    cutoff :划分拒绝/通过的点        return :好坏用户的得分分布图    """        plt.figure(figsize=plt_size)    x1 = df[df[target]==1][score_col]    x2 = df[df[target]==0][score_col]    sns.kdeplot(x1,shade=True,label='坏用户',color='hotpink')    sns.kdeplot(x2,shade=True,label='好用户',color ='seagreen')    plt.axvline(x=cutoff)    plt.legend()    return plt.show()

4.得分明细表

  按分数段区分,看不同分数段的好坏样本情况、违约率等指标。

  可以看到高分段的违约概率明显比低分段低,说明评分卡的效果是显著的。

# 得分明细表def score_info(df,score_col,target,x=None,y=None,step=None):    """    df:数据集    target:目标变量的字段名    score_col:最终得分的字段名    x:最小区间的左值    y:最大区间的右值    step:区间的分数间隔        return :得分明细表    """    df['score_bin'] = pd.cut(df[score_col],bins=np.arange(x,y,step),right=True)    total = df[target].count()    bad = df[target].sum()    good = total - bad        group = df.groupby('score_bin')    score_info_df = pd.DataFrame()    score_info_df['用户数'] = group[target].count()    score_info_df['坏用户'] = group[target].sum()    score_info_df['好用户'] = score_info_df['用户数']-score_info_df['坏用户']    score_info_df['违约占比'] = score_info_df['坏用户']/score_info_df['用户数']    score_info_df['累计用户'] = score_info_df['用户数'].cumsum()    score_info_df['坏用户累计'] = score_info_df['坏用户'].cumsum()    score_info_df['好用户累计'] = score_info_df['好用户'].cumsum()    score_info_df['坏用户累计占比'] = score_info_df['坏用户累计']/bad    score_info_df['好用户累计占比'] = score_info_df['好用户累计']/good    score_info_df['累计用户占比'] = score_info_df['累计用户']/total    score_info_df['累计违约占比'] = score_info_df['坏用户累计']/score_info_df['累计用户']    score_info_df = score_info_df.reset_index()    return score_info_df

5.提升图和洛伦兹曲线

  假设目前有10000个样本,坏用户占比为30%,我们做了一个评分卡(分数越低,用户坏的概率越高),按照评分从低到高划分成10等份(每个等份用户数为1000),计算每等份的坏用户占比,如果评分卡效果很好,那么越靠前的等份里,包含的坏用户应该越多,越靠后的等份里,包含的坏用户应该要更少。作为对比,如果不对用户评分,按照总体坏用户占比30%来算,每个等份中坏用户占比也是30%。将这两种方法的每等份坏用户占比放在一张柱状图上进行对比,就是提升图。

  将这两种方法的累计坏用户占比放在一张曲线图上,就是洛伦兹曲线图。

  此外,洛伦兹曲线可以比较两个评分卡的优劣,例如下图中虚线对应的分数假设是600分,那么在600分这cutoff点下,A和B的拒绝率都是40%,但A可以拒绝掉88%的坏用户,B只能拒掉78%的坏用户,说明A评分卡的效果更好。

# 绘制提升图和洛伦兹曲线def plot_lifting(df,score_col,target,bins=10,plt_size=None):    """    df:数据集,包含最终的得分    score_col:最终分数的字段名    target:目标变量名    bins:分数划分成的等份数    plt_size:绘图尺寸        return:提升图和洛伦兹曲线    """    score_list = list(df[score_col])    label_list = list(df[target])    items = sorted(zip(score_list,label_list),key = lambda x:x[0])    step = round(df.shape[0]/bins,0)    bad = df[target].sum()    all_badrate = float(1/bins)    all_badrate_list = [all_badrate]*bins    all_badrate_cum = list(np.cumsum(all_badrate_list))    all_badrate_cum.insert(0,0)        score_bin_list=[]    bad_rate_list = []    for i in range(0,bins,1):        index_a = int(i*step)        index_b = int((i+1)*step)        score = [x[0] for x in items[index_a:index_b]]        tup1 = (min(score),)        tup2 = (max(score),)        score_bin = tup1+tup2        score_bin_list.append(score_bin)        label_bin = [x[1] for x in items[index_a:index_b]]        bin_bad = sum(label_bin)        bin_bad_rate = bin_bad/bad        bad_rate_list.append(bin_bad_rate)    bad_rate_cumsum = list(np.cumsum(bad_rate_list))    bad_rate_cumsum.insert(0,0)        plt.figure(figsize=plt_size)    x = score_bin_list    y1 = bad_rate_list    y2 = all_badrate_list    y3 = bad_rate_cumsum    y4 = all_badrate_cum    plt.subplot(1,2,1)    plt.title('提升图')    plt.xticks(np.arange(bins)+0.15,x,rotation=90)    bar_width= 0.3    plt.bar(np.arange(bins),y1,width=bar_width,color='hotpink',label='score_card')    plt.bar(np.arange(bins)+bar_width,y2,width=bar_width,color='seagreen',label='random')    plt.legend(loc='best')    plt.subplot(1,2,2)    plt.title('洛伦兹曲线图')    plt.plot(y3,color='hotpink',label='score_card')    plt.plot(y4,color='seagreen',label='random')    plt.xticks(np.arange(bins+1),rotation=0)    plt.legend(loc='best')    return plt.show()plot_lifting(trainData,'score','y',bins=10,plt_size=(10,5))

6.设定cutoff

  cutoff即根据评分划分通过/拒绝的点,其实就是看不同的阈值下混淆矩阵的情况。设定cutoff时有两个指标,一个是误伤率,即FPR,就是好客户中有多少被预测为坏客户而拒绝。另一个是拒绝率,就是这样划分的情况下有多少客户被拒绝。

# 设定cutoff点,衡量有效性def rule_verify(df,col_score,target,cutoff):    """    df:数据集    target:目标变量的字段名    col_score:最终得分的字段名    cutoff :划分拒绝/通过的点        return :混淆矩阵    """    df['result'] = df.apply(lambda x:30 if x[col_score]<=cutoff else 10,axis=1)    TP = df[(df['result']==30)&(df[target]==1)].shape[0]    FN = df[(df['result']==30)&(df[target]==0)].shape[0]    bad = df[df[target]==1].shape[0]    good = df[df[target]==0].shape[0]    refuse = df[df['result']==30].shape[0]    passed = df[df['result']==10].shape[0]        acc = round(TP/refuse,3)    tpr = round(TP/bad,3)    fpr = round(FN/good,3)    pass_rate = round(refuse/df.shape[0],3)    matrix_df = pd.pivot_table(df,index='result',columns=target,aggfunc={col_score:pd.Series.count},values=col_score)        print('精确率:{}'.format(acc))    print('查全率:{}'.format(tpr))    print('误伤率:{}'.format(fpr))    print('规则拒绝率:{}'.format(pass_rate))    return matrix_df

回归模型的score得分为负_逻辑回归评分卡实现和评估相关推荐

  1. 回归模型的score得分为负_SPSS中 回归 B值为负数什么意思

    展开全部 B值是指回归系数和截距(常数项),可以是负数(负相关时回归系数出现负值).e5a48de588b63231313335323631343130323136353331333431366262 ...

  2. 回归模型的score得分为负_Sklearn模型中预测值的R2_score为负数的问题探讨

    Sklearn.metrics下面的r2_score函数用于计算R²(确定系数:coefficient of determination).它用来度量未来的样本是否可能通过模型被很好地预测.分值为1表 ...

  3. R语言计算F1评估指标实战:F1 score、使用R中caret包中的confusionMatrix()函数为给定的logistic回归模型计算F1得分(和其他指标)

    R语言计算F1评估指标实战:F1 score.使用R中caret包中的confusionMatrix()函数为给定的logistic回归模型计算F1得分(和其他指标) 目录

  4. 常用于评价回归模型优劣的统计量包括( )。_第四十一讲 R-判断回归模型性能的指标...

    当回归模型建立好以后,如何评价该回归模型是否与另一个回归模型有区别,如何比较两个回归模型的性能?这一讲中,我们将给大家介绍几个评价回归模型性能的统计指标. 1. 模型性能指标 在回归模型中,最常用的评 ...

  5. R语言survival包coxph函数构建cox回归模型、ggrisk包ggrisk函数可视化Cox回归的风险评分图、使用风险得分的中位数计算最佳截断值cutoff(基于LIRI基因数据集)

    R语言survival包coxph函数构建cox回归模型.ggrisk包ggrisk函数可视化Cox回归的风险评分图.使用风险得分的中位数计算最佳截断值cutoff(基于LIRI基因数据集) 目录

  6. 机器学习系列(1)_逻辑回归初步

    转载自: 机器学习系列(1)_逻辑回归初步 - 寒小阳 - 博客频道 - CSDN.NET http://blog.csdn.net/han_xiaoyang/article/details/4912 ...

  7. python实现逻辑回归算法_逻辑回归算法的实现

    前言 在之前的学习中,我们已经学习了逻辑回归算法的具体数学原理及其简单的推导过程,现在,我们可以用python实现逻辑回归的算法了. 环境 python3.6 jupyter-notebook 绘制数 ...

  8. 逻辑回归优点_逻辑回归:优点

    逻辑回归优点 by Thalles Silva 由Thalles Silva 逻辑回归:优点 (Logistic Regression: The good parts) 您需要了解的所有信息. (Ev ...

  9. 逻辑回归评分卡实现和评估

    评分卡实现和评估   上一节讲得是模型评估,主要有ROC曲线.KS曲线.学习曲线和混淆矩阵.今天学习如何实现评分卡和对评分卡进行评估.   首先,要了解评分卡是如何从概率映射到评分的,这个之前写过评分 ...

最新文章

  1. 【转】推荐计算机科学类的经典书籍 3
  2. 物理主机安装linux的方法
  3. flash 游戏 ui 制作方案
  4. 程序员养生:熬夜指南
  5. 如何使用github搭建个人博客
  6. 子主题function php,php – 带有依赖项的子主题
  7. 【C语言】数组名作函数参数,完成数据的升序排列
  8. 演讲(2)----十大范畴法
  9. C++接收字符串数组_Java 中初始化数组
  10. IT人必去的几大网站,国内外知名IT网站罗列!
  11. leetcode886.PossibleBipartition
  12. 【BAT】中文数字to阿拉伯数字转换
  13. Vue 2.0 + Axios + Vue Router 实现CNode社区
  14. php算法-输出100以内能被3整除的整数
  15. 2020年中国办公软件行业市场现状分析,多端协作化、智能化、集成化是方向「图」
  16. c语言 结构体数组嵌套另一个结构体数组怎么初始化?,如何初始化结构体数组(内嵌结构体)...
  17. 英语语法篇 - 动词的分类和形式
  18. 用c语言用*组成C字母,C语言字符集由字母,数字,空格,标点符号和特殊字符组成...
  19. 画彩色斐波那契螺旋线
  20. phpExcel单元格内换行

热门文章

  1. HTML的基本知识-和常用标签-以及相对路径和绝对路径的区别
  2. 有很帅气的微信头像推荐吗?
  3. 2021年已经过去了4天,创业者、负债累累而希望通过再创业实现东山再起者,你们准备的怎么样了?
  4. 企业创新流程的“正向推”与“反向推”思考
  5. 混迹职场,有交换意识的人都是聪明人
  6. 如果你现在很穷,很苦,不要苦恼
  7. 据报道称“浏览器内核有上千万行代码”,浏览器内核真的很复杂吗?
  8. Apple’s current market value is more than two trillion
  9. HTML中常见问题汇总贴
  10. 题解 CF1391A 【Suborrays】