利用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 02 Python
Python映射拆分操作符用法实例
May 19 Python
python+pygame简单画板实现代码实例
Dec 13 Python
python读取文件名称生成list的方法
Apr 27 Python
Python一句代码实现找出所有水仙花数的方法
Nov 13 Python
对Python生成汉字字库文字,以及转换为文字图片的实例详解
Jan 29 Python
浅析Django中关于session的使用
Dec 30 Python
python关于变量名的基础知识点
Mar 03 Python
利用Python裁切tiff图像且读取tiff,shp文件的实例
Mar 10 Python
如何使用python切换hosts文件
Apr 29 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
Jul 02 Python
python3处理word文档实例分析
Dec 01 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
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
编译PHP报错configure error Cannot find libmysqlclient under usr的解决方法
2014/06/27 PHP
PHP实现取得HTTP请求的原文
2014/08/18 PHP
php检测url是否存在的方法
2015/04/14 PHP
PHP5.4起内置web服务器使用方法
2016/08/09 PHP
详解EventDispatcher事件分发组件
2016/12/25 PHP
PHP命令空间namespace及use的用法小结
2017/11/27 PHP
在Laravel 的 Blade 模版中实现定义变量
2019/10/14 PHP
jquery 操作日期、星期、元素的追加的实现代码
2012/02/07 Javascript
javascript和jquery修改a标签的href属性
2013/12/16 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
2014/02/26 Javascript
通过$(this)使用jQuery包装后的方法或属性
2014/05/18 Javascript
百度判断手机终端并自动跳转js代码及使用实例
2014/06/11 Javascript
javascript工厂方式定义对象
2014/12/26 Javascript
jQuery简单获取键盘事件的方法
2016/01/22 Javascript
jQuery+CSS实现一个侧滑导航菜单代码
2016/05/09 Javascript
angular directive的简单使用总结
2017/05/24 Javascript
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
jQuery单页面文字搜索插件jquery.fullsearch.js的使用方法
2020/02/04 jQuery
[02:53]DOTA2亚洲邀请赛 NewBee战队巡礼
2015/02/03 DOTA
Python实现复杂对象转JSON的方法示例
2017/06/22 Python
Python及PyCharm下载与安装教程
2017/11/18 Python
Python内置random模块生成随机数的方法
2019/05/31 Python
python 定义类时,实现内部方法的互相调用
2019/12/25 Python
python 发送邮件的示例代码(Python2/3都可以直接使用)
2020/12/03 Python
全球性的众包图形设计市场:DesignCrowd
2021/02/02 全球购物
中专毕业生个人职业生涯规划
2014/02/19 职场文书
计算机售后服务承诺书
2014/05/30 职场文书
培训督导岗位职责
2015/04/10 职场文书
奔腾年代观后感
2015/06/09 职场文书
《中华上下五千年》读后感3篇
2019/11/29 职场文书
Python实战之用tkinter库做一个鼠标模拟点击器
2021/04/27 Python
浅谈Python实现opencv之图片色素的数值运算和逻辑运算
2021/06/23 Python
html输入两个数实现加减乘除功能
2021/07/01 HTML / CSS
Java基于Dijkstra算法实现校园导游程序
2022/03/17 Java/Android
SQL Server #{}可以防止SQL注入
2022/05/11 SQL Server