利用Python计算KS的实例详解


Posted in Python onMarch 03, 2020

在金融领域中,我们的y值和预测得到的违约概率刚好是两个分布未知的两个分布。好的信用风控模型一般从准确性、稳定性和可解释性来评估模型。

一般来说。好人样本的分布同坏人样本的分布应该是有很大不同的,KS正好是有效性指标中的区分能力指标:KS用于模型风险区分能力进行评估,KS指标衡量的是好坏样本累计分布之间的差值。

好坏样本累计差异越大,KS指标越大,那么模型的风险区分能力越强。

1、crosstab实现,计算ks的核心就是好坏人的累积概率分布,我们采用pandas.crosstab函数来计算累积概率分布。

2、roc_curve实现,sklearn库中的roc_curve函数计算roc和auc时,计算过程中已经得到好坏人的累积概率分布,同时我们利用sklearn.metrics.roc_curve来计算ks值

3、ks_2samp实现,调用stats.ks_2samp()函数来计算。链接scipy.stats.ks_2samp¶为ks_2samp()实现源码,这里实现了详细过程

4、直接调用stats.ks_2samp()计算ks

import pandas as pd 
import numpy as np
from sklearn.metrics import roc_curve
from scipy.stats import ks_2samp
 
def ks_calc_cross(data,pred,y_label):
  '''
  功能: 计算KS值,输出对应分割点和累计分布函数曲线图
  输入值:
  data: 二维数组或dataframe,包括模型得分和真实的标签
  pred: 一维数组或series,代表模型得分(一般为预测正类的概率)
  y_label: 一维数组或series,代表真实的标签({0,1}或{-1,1})
  输出值:
  'ks': KS值,'crossdens': 好坏客户累积概率分布以及其差值gap
  '''
  crossfreq = pd.crosstab(data[pred[0]],data[y_label[0]])
  crossdens = crossfreq.cumsum(axis=0) / crossfreq.sum()
  crossdens['gap'] = abs(crossdens[0] - crossdens[1])
  ks = crossdens[crossdens['gap'] == crossdens['gap'].max()]
  return ks,crossdens
 
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[0]],data[pred[0]])
  ks = max(tpr-fpr)
  return ks
 
def ks_calc_2samp(data,pred,y_label):
  '''
  功能: 计算KS值,输出对应分割点和累计分布函数曲线图
  输入值:
  data: 二维数组或dataframe,包括模型得分和真实的标签
  pred: 一维数组或series,代表模型得分(一般为预测正类的概率)
  y_label: 一维数组或series,代表真实的标签({0,1}或{-1,1})
  输出值:
  'ks': KS值,'cdf_df': 好坏客户累积概率分布以及其差值gap
  '''
  Bad = data.loc[data[y_label[0]]==1,pred[0]]
  Good = data.loc[data[y_label[0]]==0, pred[0]]
  data1 = Bad.values
  data2 = Good.values
  n1 = data1.shape[0]
  n2 = data2.shape[0]
  data1 = np.sort(data1)
  data2 = np.sort(data2)
  data_all = np.concatenate([data1,data2])
  cdf1 = np.searchsorted(data1,data_all,side='right')/(1.0*n1)
  cdf2 = (np.searchsorted(data2,data_all,side='right'))/(1.0*n2)
  ks = np.max(np.absolute(cdf1-cdf2))
  cdf1_df = pd.DataFrame(cdf1)
  cdf2_df = pd.DataFrame(cdf2)
  cdf_df = pd.concat([cdf1_df,cdf2_df],axis = 1)
  cdf_df.columns = ['cdf_Bad','cdf_Good']
  cdf_df['gap'] = cdf_df['cdf_Bad']-cdf_df['cdf_Good']
  return ks,cdf_df
 
data = {'y_label':[1,1,1,1,1,1,0,0,0,0,0,0],
    'pred':[0.5,0.6,0.7,0.6,0.6,0.8,0.4,0.2,0.1,0.4,0.3,0.9]}
 
data = pd.DataFrame(data)
ks1,crossdens=ks_calc_cross(data,['pred'], ['y_label'])
 
ks2=ks_calc_auc(data,['pred'], ['y_label'])
 
ks3=ks_calc_2samp(data,['pred'], ['y_label'])
 
get_ks = lambda y_pred,y_true: ks_2samp(y_pred[y_true==1], y_pred[y_true!=1]).statistic
ks4=get_ks(data['pred'],data['y_label'])
print('KS1:',ks1['gap'].values)
print('KS2:',ks2)
print('KS3:',ks3[0])
print('KS4:',ks4)

输出结果:

KS1: [ 0.83333333]
KS2: 0.833333333333
KS3: 0.833333333333
KS4: 0.833333333333

当数据中存在NAN数据时,有一些问题需要注意!

例如,我们在原数据中增加了y_label=0,pred=np.nan这样一组数据

data = {'y_label':[1,1,1,1,1,1,0,0,0,0,0,0,0],
'pred':[0.5,0.6,0.7,0.6,0.6,0.8,0.4,0.2,0.1,0.4,0.3,0.9,np.nan]}

此时执行

ks1,crossdens=ks_calc_cross(data,['pred'], ['y_label'])

输出结果

KS1: [ 0.83333333]

执行

ks2=ks_calc_auc(data,['pred'], ['y_label'])

将会报以下错误

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

执行

ks3=ks_calc_2samp(data,['pred'], ['y_label'])

输出结果

KS3: 0.714285714286

执行

ks4=get_ks(data['pred'],data['y_label'])

输出结果

KS4: 0.714285714286

我们从上述结果中可以看出

三种方法计算得到的ks值均不相同。

ks_calc_cross计算时忽略了NAN,计算得到了数据正确的概率分布,计算的ks与我们手算的ks相同

ks_calc_auc函数由于内置函数无法处理NAN值,直接报错了,所以如果需要ks_calc_auc计算ks值时,需要提前去除NAN值。

ks_calc_2samp计算得到的ks因为searchsorted()函数(有兴趣的同学可以自己模拟数据看下这个函数),会将Nan值默认排序为最大值,从而改变了数据的原始累积分布概率,导致计算得到的ks和真实的ks有误差。

总结

在实际情况下,我们一般计算违约概率的ks值,这时是不存在NAN值的。所以以上三种方法计算ks值均可。但是当我们计算单变量的ks值时,有时数据质量不好,存在NAN值时,继续采用ks_calc_auc和ks_calc_2samp就会存在问题。

解决办法有两个

1. 提前去除数据中的NAN值

2. 直接采用ks_calc_cross计算。

以上这篇利用Python计算KS的实例详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中使用dom模块生成XML文件示例
Apr 05 Python
详解Python 数据库 (sqlite3)应用
Dec 07 Python
python版本的仿windows计划任务工具
Apr 30 Python
python验证码识别教程之利用滴水算法分割图片
Jun 05 Python
解决Python中定时任务线程无法自动退出的问题
Feb 18 Python
Django CBV类的用法详解
Jul 26 Python
python 队列基本定义与使用方法【初始化、赋值、判断等】
Oct 24 Python
python找出列表中大于某个阈值的数据段示例
Nov 24 Python
Python实现遗传算法(二进制编码)求函数最优值方式
Feb 11 Python
jupyter notebook tensorflow打印device信息实例
Apr 20 Python
你应该知道的Python3.6、3.7、3.8新特性小结
May 12 Python
Django之富文本(获取内容,设置内容方式)
May 21 Python
python如何提取英语pdf内容并翻译
Mar 03 #Python
Pycharm如何运行.py文件的方法步骤
Mar 03 #Python
python生成大写32位uuid代码
Mar 03 #Python
python str字符串转uuid实例
Mar 03 #Python
PyCharm取消波浪线、下划线和中划线的实现
Mar 03 #Python
python生成并处理uuid的实现方式
Mar 03 #Python
python实现在线翻译功能
Mar 03 #Python
You might like
咖啡的植物学知识
2021/03/03 咖啡文化
关于Appserv无法打开localhost问题的解决方法
2009/10/16 PHP
php 根据url自动生成缩略图并处理高并发问题
2014/01/23 PHP
PHP读取CURL模拟登录时生成Cookie文件的方法
2014/11/04 PHP
PHP下的浮点运算不准的解决方法
2016/10/27 PHP
php检查函数必传参数是否存在的实例详解
2017/08/28 PHP
PHP实现文字写入图片功能
2019/02/18 PHP
php更新cookie内容的详细方法
2019/09/30 PHP
PHP设计模式入门之状态模式原理与实现方法分析
2020/04/26 PHP
客户端脚本中常常出现的一些问题和调试技巧
2007/01/09 Javascript
10个基于jQuery或JavaScript的WYSIWYG 编辑器整理
2010/05/06 Javascript
Javascript无阻塞加载具体方式
2013/06/28 Javascript
浏览器图片选择预览、旋转、批量上传的JS代码实现
2013/12/04 Javascript
利用JS来控制键盘的上下左右键(示例代码)
2013/12/14 Javascript
IE6下javasc#ipt:void(0) 无效的解决方法
2013/12/23 Javascript
基于jQuery1.9版本如何判断浏览器版本类型
2016/01/12 Javascript
js html5 css俄罗斯方块游戏再现
2016/10/17 Javascript
jQuery实现的简单日历组件定义与用法示例
2018/12/24 jQuery
node.js中stream流中可读流和可写流的实现与使用方法实例分析
2020/02/13 Javascript
JavaScript 常见的继承方式汇总
2020/09/17 Javascript
[05:45]Ti4观战指南(下)
2014/07/07 DOTA
Flask入门教程实例:搭建一个静态博客
2015/03/27 Python
利用Python爬虫给孩子起个好名字
2017/02/14 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
Django网络框架之HelloDjango项目创建教程
2019/06/06 Python
python+Django+pycharm+mysql 搭建首个web项目详解
2019/11/29 Python
CSS3绘制有活力的链接下划线
2016/07/14 HTML / CSS
用HTML5中的Canvas结合公式绘制粒子运动的教程
2015/05/08 HTML / CSS
美国宠物用品网站:Value Pet Supplies
2018/03/17 全球购物
康拓普公司Java笔面试
2016/09/23 面试题
端口镜像是怎么实现的
2014/03/25 面试题
大学生工作推荐信范文
2013/12/02 职场文书
技术总监管理岗位职责
2014/03/09 职场文书
2014年村官工作总结
2014/11/24 职场文书
企业战略合作意向书
2015/05/08 职场文书
mysql批量新增和存储的方法实例
2021/04/07 MySQL