利用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实现俄罗斯方块游戏
Mar 25 Python
详解Python3中的迭代器和生成器及其区别
Oct 09 Python
使用python对文件中的数值进行累加的实例
Nov 28 Python
Python设计模式之享元模式原理与用法实例分析
Jan 11 Python
python 列表中[ ]中冒号‘:’的作用
Apr 30 Python
Django urls.py重构及参数传递详解
Jul 23 Python
python实现邮件自动发送
Aug 10 Python
python实现从ftp服务器下载文件
Mar 03 Python
基于Python3.7.1无法导入Numpy的解决方式
Mar 09 Python
Python map及filter函数使用方法解析
Aug 06 Python
详解基于python的图像Gabor变换及特征提取
Oct 26 Python
python 实现围棋游戏(纯tkinter gui)
Nov 13 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
PHP5.2中date()函数显示时间与北京时间相差8小时的解决办法
2009/05/28 PHP
php中防止恶意刷新页面的代码小结
2012/10/31 PHP
php实现XML和数组的相互转化功能示例
2017/02/08 PHP
Laravel如何友好的修改.env配置文件详解
2017/06/07 PHP
php的instanceof和判断闭包Closure操作示例
2020/01/26 PHP
详解phpstorm2020最新破解方法
2020/09/17 PHP
让浏览器非阻塞加载javascript的几种方法小结
2011/04/25 Javascript
js 本地预览的简单实现方法
2014/02/18 Javascript
js交换排序 冒泡排序算法(Javascript版)
2014/10/04 Javascript
javascript学习笔记(五)原型和原型链详解
2014/10/08 Javascript
微信小程序 教程之数据绑定
2016/10/18 Javascript
微信小程序 radio单选框组件详解及实例代码
2017/01/10 Javascript
bootstrap折叠调用collapse()后data-parent不生效的快速解决办法
2017/02/23 Javascript
详解mpvue scroll-view自动回弹bug解决方案
2018/10/01 Javascript
vscode 开发Vue项目的方法步骤
2018/11/25 Javascript
详解Vue-axios 设置请求头问题
2018/12/06 Javascript
js构造函数constructor和原型prototype原理与用法实例分析
2020/03/02 Javascript
python函数装饰器用法实例详解
2015/06/04 Python
关于numpy中np.nonzero()函数用法的详解
2017/02/07 Python
高质量Python代码编写的5个优化技巧
2017/11/16 Python
python实现微信每日一句自动发送给喜欢的人
2019/04/29 Python
Python将列表中的元素转化为数字并排序的示例
2019/12/25 Python
python实现吃苹果小游戏
2020/03/21 Python
简单介绍HTML5中audio标签的使用
2015/09/24 HTML / CSS
匡威爱尔兰官网:Converse爱尔兰
2019/06/09 全球购物
俄罗斯金苹果网上化妆品和香水商店:Goldapple
2019/12/01 全球购物
.net工程师笔试题
2012/06/09 面试题
违反课堂纪律检讨书
2014/01/19 职场文书
幼儿园秋游活动方案
2014/01/21 职场文书
优秀学生党员先进事迹材料
2014/05/29 职场文书
总经理检讨书
2014/09/15 职场文书
夫妻双方自愿离婚协议书
2014/10/24 职场文书
2019学校运动会开幕词
2019/05/13 职场文书
某学校的2019年度工作报告范本
2019/10/11 职场文书
创业计划书之酒厂
2019/10/14 职场文书
Anaconda安装pytorch及配置PyCharm 2021环境
2021/06/04 Python