风控模型评估指标:KS、ROC、AUC、PSI代码逻辑

风控模型评估指标:KS、ROC、AUC、PSI代码逻辑_第1张图片
上图中,我们最常用的就是TPR(True Positive Rate)和FPR(False Positive Rate):

其中:

TPR = TP/(TP+FN)即真实1中预测错的;

FPR = FP/(FP+TN)即真实0中预测错的;

Precision = TP/(TP+FP)即预测1中对的

最理想的模型,是TPR尽量高而FPR尽量低,然而任何模型在提高正确预测概率的同时,也会难以避免地增加误判率。听起来有点抽象,好在有ROC曲线非常形象地表达了二者之间的关系。

ROC曲线是以FPR为横轴,TPR为纵轴,在不同阈值下计算FPR和TPR的值画出的图形。
AUC就是ROC曲线下方的面积,值一般在0.5-1.0之间。值越大表示模型判断准确性越高,即越接近1越好。ROC=0.5表示模型的预测能力与随机结果没有差别。
KS值表示了模型将 和-区分开来的能力。值越大,模型的预测准确性越好。一般,KS>0.2即可认为模型有比较好的预测准确性。

KS曲线与ROC有着相同的作用:

KS曲线是将概率从小到大进行排序,取10%的值为阈值,同理将10%*k(k=1,…9)处值作为阈值,计算不同的FPR和TPR,以10%*k(k=1,…9)为横坐标,同时分别以TPR和FPR为纵坐标画出两条曲线就是KS曲线。而KS值=|max(TPR-FPR)|。详细的可以参考网址:https://www.sohu.com/a/132667664_278472

风控模型评估指标:KS、ROC、AUC、PSI代码逻辑_第2张图片

另外,还有另一种计算KS值的方法:

将所有的样本根据分数值从低到高排序均分成20组,分别计算20组的实际好样本数、实际坏样本数、累积好样本数、累积坏样本数、累积好样本数占比、累积坏样本数占比、差值。其中,实际好坏样本数分别为该组内的好坏样本数;累积好坏样本数为该组累积好坏样本数;累积好坏样本数占比为累积好坏样本数占总好坏样本数的比值;差值为累积坏样本数占比 - 累积好样本数占比。
PSI在上一篇中已经做了具体介绍,想了解的可以关注我:
风控模型评估指标:KS、ROC、AUC、PSI代码逻辑_第3张图片
实现这几个指标的python代码如下:

from sklearn.metrics import roc_curve
from scipy.stats import ks_2samp

# 计算ks值
def ks_calc_auc(data,pred,y_label):
    '''
    功能: 计算KS值,输出对应分割点和累计分布函数曲线图
    输入值:
    data: 二维数组或dataframe,包括模型得分和真实的标签
    pred: 一维数组或series,代表模型得分(一般为预测正类的概率)
    y_label: 一维数组或series,代表真实的标签({0,1}或{-1,1})
    输出值:
    'ks': KS值
    '''
    fpr,tpr,thresholds= roc_curve(data[y_label],data[pred])
    ks = max(tpr-fpr)
    return ks

# 计算AUC值
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, roc_auc_score
def roc_auc_z(data,pred,y_label):
    # 计算auc的值
    fpr,tpr,thresholds= roc_curve(data[y_label],data[pred])
    auc_score=roc_auc_score(data[y_label],data[pred])
    return auc_score


def target_total(df,nameks,date,lable): # nameks特征名字
    # nameks特征名字
    # date分组日期:如:"月份"
    # lable就是y变量
    
    
    ## 为了计算psi
    labels=['c'+str(i) for i in range(10)]
    # True_out,bins=pd.qcut(df['result'],q=10,retbins=True,labels=labels, duplicates='drop')
    True_out,bins=pd.cut(df['result'],bins=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],retbins=True, labels=labels)
    df['True_out'] = True_out
    # bins[0] = bins[0]-0.001 #cut左开右闭,之前最小值再分组后组记号为空,这里减0.01划到最左侧区间
    
    ksdf = pd.DataFrame(columns=['月份'])
    month = []
    week = []
    ks = []
    roc = []
    psi = []
    for i in range(len(df[date].unique())):
        w = df[date].unique()[i]
        data_ks = df.loc[df[date] == w,]
        m = data_ks['月份'].unique()[0]
        # 计算ks值
        ks_z = ks_calc_auc(data_ks,'result',lable)
        # 计算roc_auc值
        roc_z = roc_auc_z(data_ks,'result',lable)
        
        # 计算psi值
        if len(df[date].unique())>=3:
            data_psi_last = df.loc[(df[date] <= df[date].unique()[2]),]
        else:
            fri_m = df['月份'].unique()[0]
            data_psi_last = df.loc[(df['月份'] == fri_m),]
        
        a=pd.DataFrame(data_psi_last.True_out.value_counts()).rename(columns={'True_out':'基准占比'})
        a=a.applymap(lambda y : y/sum(a.基准占比))

        b=pd.DataFrame(data_ks.True_out.value_counts()).rename(columns={'True_out':'当月占比'})
        b=b.applymap(lambda y : y/sum(b.当月占比))

        re=pd.merge(a,b,left_index=True,right_index=True)
        
        psi_z=0
        for k in range(len(re)):
            if re['基准占比'][k]==0:
                re['基准占比'][k]=0.000001
            if re['当月占比'][k]==0:
                re['当月占比'][k]=0.000001
            l=math.log((re['当月占比'][k]/re['基准占比'][k]))
            p=((re['当月占比'][k]-re['基准占比'][k])*(math.log((re['当月占比'][k]/re['基准占比'][k]))))
            
            psi_z=psi_z+p
        
        month.append(m)
        week.append(w)
        ks.append(ks_z)
        roc.append(roc_z)
        psi.append(psi_z)
        
    ksdf['月份'] = month
    ksdf[date] = week
    ksdf['features'] = nameks
    ksdf['ks'] = ks
    ksdf['roc'] = roc
    ksdf['psi'] = psi
    ksdf['psi'] = ksdf['psi']*100
    return ksdf

你可能感兴趣的:(python)