老饼讲解:一步一步上手学习
在二分类模型中,往往会用KS曲线(Kolmogorov-Smirnov Curve)和KS指标来评估模型的效果,本文我们就来说说KS、KS曲线分别是什么,以及KS的两种公式,进一步地,再展示一下KS的手算过程和例子,并用python代码来计算一下KS和绘画KS曲线。
KS曲线是一种用来看二分类模型效果的曲线,而KS(Kolmogorov-Smirnov )则是用来评估二分类模型效果的一个指标,可能有些同学糊里糊涂,不急,让我们慢慢道来。
我们都知道,KS曲线与KS都是服务于二分类模型的,在说它们之前,我们先来看看二分类模型的输出是什么,这样才知道KS和KS曲线计算的都是些什么。如下,二分类模型输出的是如下的评分(或者概率):

这里的评分(或者概率)指的是"样本属于正样本"的评分(或者概率),也就是它越高就代表样本越可能是正样本。而二分类模型呢,则一般会设置一个阈值,当这个评分大于所设的阈值时,就判为正样本。
KS全称为Kolmogorov-Smirnov,它的公式定义如下:
其中,
TPR(True PositiveRate)查全率 : 是 1 的样本,被检查出来的概率
FPR(False PositiveRate)虚警率 : 是 0 的样本,被误检成1的概率
可以留意到,模型取不同的阈值时,TPR和FPR就会不同,好了,那上面的KS公式是啥意思呢?其实只要把TPR看作收益,FPR看作成本,那么TPR-FPR就是利润了,而模型取不同阈值就会有不同利润,而KS呢,就是最大利润了。
为什么可以把查全率TPR当作收益,把虚警率FPR当作成本呢? 举个具体例子,例如投放广告,查全(1类被检查出来)是收益:我们成功检查出了目标客户,他们都会产生收益,而虚警(0类被误检为1类)则是成本:非目标客户被当成了目标客户,会产生不必要的投放成本。
在实际中,KS更常用的是如下计算公式,会更方便计算。
KS计算公式:
我们可以来看下公式,它其实就是分数小于阈值 的样本中,0类的占比与1类占比差距的最大值。
那么,这个计算公式是怎么得到的呢,其实只要将原始定义公式变一下形式就可以得到了:
KS计算公式-推导过程如下:
最后,我们再来看看什么是KS曲线, KS曲线如下图所示:

可以看到,以阈值为x轴,TPR、FPR、(TPR-FPR)为y轴所组成的三条变化曲线,然后标出KS的所在位置(即TPR与FPR的最大间隔点),就是KS曲线了。
我们知道,KS有两条公式,一条是定义公式,另一条是计算公式,在手算法一般用计算公式,而用代码实现时,则一般使用定义公式,这样会更加方便,下面我们来详细看看手算和代码计算分别怎么弄。
手算KS时,我们一般都使用计算公式来计算,这样会比较方便。
KS计算公式:
接下来我们再看看KS是怎么计算的,假设现在模型的预测分数和真实标签如下:

那么,根据KS计算公式,计算KS的流程如下:

需要注意的是,如上例所示,KS所对应的阈值应是下一行的0.55,而不是0.846所对应的行的0.44。这是因为上述表格统计占比时用的是"<=",而公式中需要的是"<"。
在数据量过大时,为节省计算量,可采用以下分组统计方法:
1. 按socre排序,并按大小分组,例如分为5组
2. 统计每组的(0,1)标签占比、累计占比和累计占比差异
3. 占比差异最大者,即为KS值
下面我们再来看看如何用python来计算KS,以及画KS曲线。在使用python代码计算KS时,由于sklearn的roc_curve函数提供了fpr和tpr,因此,更倾向于用定义公式计算更为简洁,也就是如下的公式:
好了,下面展示一个用python调用sklearn的roc_curve函数计算KS和绘制KS曲线的代码,具体如下:
'''
本代码用于展示如何用sklearn计算KS和画出KS曲线
本代码来自《老饼讲解-机器学习》www.bbblearn.com
'''
from sklearn.metrics import roc_curve
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# -----------数据生成----------------------------
score_dict = {'score':[0.71,0.612,0.127,0.330,0.428,0.889,0.188
,0.229,0.889,0.022,0.43,0.952,0.622,0.11
,0.22,0.33,0.44,0.55,0.66,0.77,0.88,0.99]
,'label':[1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1]} # score与label
df = pd.DataFrame(score_dict) # 将数据转为df
# -------------计算ks-----------------------------
fpr, tpr, thresholds= roc_curve(df.label, df.score) # 计算fpr, tpr
ks_value = max(abs(fpr-tpr)) # 计算KS: abs(fpr-tpr)最大者就是KS
# ----------画KS曲线-------------------------------
thresholds[0] = max(df['score'])+0.01 # 修正thresholds的最大值
plt.figure(figsize=(10, 5)) # 设置图片的大小
plt.plot(thresholds,fpr, label='fpr') # 标示fpr
plt.plot(thresholds,tpr, label='tpr') # 标示tpr
plt.plot(thresholds,abs(fpr-tpr), label='fpr-tpr') # 标示fpr-tpr
plt.xlabel('thresholds') # 标示x坐标轴
# 标记ks
idx = np.argwhere(abs(fpr-tpr) == ks_value)[0, 0] # 找最KS的位置
ks_threshold = thresholds[idx] # KS所对应的阈值
plt.plot((ks_threshold, ks_threshold), (fpr[idx], tpr[idx]),
label='ks - {:.2f}'.format(ks_value),
color='r', marker='o', markerfacecolor='r', markersize=5) # 画出KS曲线
plt.scatter((ks_threshold,ks_threshold),(fpr[idx], tpr[idx]), color='r') # 标出KS
plt.legend() # 展示图例
plt.show() # 展示画布
print('阈值:',ks_threshold) # 打印阈值
print('KS:',ks_value) # 打印KS代码运行结果如下:


可以看到,它和我们上面手算的结果是一样的。而在这个例子里KS曲线不怎么好看,是因为数据比较少,多一点数据,它就是比较平滑了。
看起来内容很多,其实很少,无非是KS的意义就是利润的最大值:max(TPR-FPR),而KS曲线就是把相关的几个曲线、以及KS展示出来,在具体计算KS时,可以手算,也可以用代码实现,手算一般用手算的公式,而用代码实现则一般用定义的公式来计算,简简单单。
评论