无论评分卡建模和是机器学习建模,最终的输出结果都是概率值,并不是一个特定范围的分数,现给大家介绍一个方法。

1.基本定义

坏用户的概率为P
好用户的概率为1-P
好坏比(好坏用户的比值叫比率,这里用坏用户与好用户的比值)odds=p/(1-p)
模型的评分设定的分值刻度可以通过将分值表示为比率对数的线性表达式,即

Score = A - B * ln(odds),其中A,B是常数

2.评分转换

设odds=p/(1-p)时对应的分数为Score
设定当每增加1倍时,增加的分数PDO(point of double odds),即比率翻番的倍数
将odds=p/(1-p)对应的分数Score,2*odds对应的分数Score + PDO,带入分数公式得到如下的两个公式:

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

此时给定比率odds=1/20,即此时坏样本占比为1/(1+20)≈ 4.76%,对应的分数为800分,比率翻番的倍数PDO=50.

def cfunc(ratio,basescore,double):
    x = Symbol('x')
    y = Symbol('y')
    out = solve([basescore -(x-y * np.log(ratio)), basescore -(x-y * np.log(2*ratio) + double)], [x, y])
    a = np.round(float(out.get(x)),2)
    b = np.round(float(out.get(y)),2)
    title = str(a) + '-' + str(b) + '*log(odds)'
    score_i = []
    score_j = []
    for i in np.arange(0.10,1.,0.10):
        score_sig = out.get(x) - out.get(y) * np.log(i /(1-i))
        score_i.append(int(score_sig))
    score_prob = pd.DataFrame({'prob':np.arange(0.10,1.00,0.10),'score':score_i})
    for j in [0.01,0.05,0.95,0.99]:
        score_sig = out.get(x) - out.get(y) * np.log(j / (1 - j))
        if score_sig > 850:
            score_sig = 850
        elif score_sig < 300:
            score_sig = 300
        else:
            score_sig = score_sig
        score_j.append(int(score_sig))
    score_prob_j = pd.DataFrame({'prob': [0.01,0.05,0.95,0.99], 'score': score_j})
    score_prob = score_prob.append(score_prob_j).sort_values(['prob'],ascending=False)
    # plot and save
    filepath = os.path.split(os.path.realpath(__file__))[0] + '\output'
    if not os.path.exists(filepath):
        os.mkdir(filepath)
    prob_plot(score_prob, title,filepath)

    return score_prob

注:为了将分数限定在300~850之间,将过大或过小的分数采用盖帽法原理予以限制

最终将坏样本的概率与分数对应的关系,通过折线图体现出来

def prob_plot(score_prob,title,filepath):
    import matplotlib.pyplot as plt
    plt.plot(score_prob.prob, score_prob.score, marker='o', mec='r', mfc='w', label='prob_to_score')
    plt.legend(loc=0)
    plt.plot(np.ones(score_prob.shape[0]) * 0.5, score_prob.score, mfc='r')
    for c, d in zip(score_prob.prob, score_prob.score):
        plt.text(c, d + 0.3, str(round(d)), ha='left', va='bottom', fontsize=10.5)
    plt.xticks(np.arange(0.00, 1.01, 0.10))
    plt.yticks(np.arange(0, 1001, 100))
    # plt.margins(0)
    plt.subplots_adjust(bottom=0.10)
    plt.title(title)
    plt.xlabel('prob')
    plt.ylabel("score")
    plt.savefig((filepath + '/{title}.jpg').format(title=str(title)[-3:-1]),dpi=900)

结果如下:
在这里插入图片描述

感兴趣的小伙伴可以自己设置不同的odds、Score和PDO,得到不同的比例关系

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐