使用PySpark计算AUC,KS与PSI
当特征数量或者模型数量很多的时候,使用PySpark去计算相关指标会节省很多的时间。网上关于使用PySpark计算相关指标的资料较少,这里抛砖引玉,写了三个风控常用的指标AUC,KS和PSI相关的计算方法,供参考。
AUC
AUC的相关概念网上已经有很多的很好的文章,这里不在赘述,AUC使用的到的计算公式如下:
\]
其中M为负类样本的数目,N为正类样本的数目
使用PySpark计算代码如下:
from pyspark.sql import functions as F
from pyspark.sql.window import Window
true_y_col = 'y'
pred_y_col = 'pred_y'
date_col = 'day'
auc_df = df.filter(F.col(true_y_col)>=0).filter(F.col(pred_y_col)>=0)\
.select(true_y_col, pred_y_col, date_col, 'model_name')\
.withColumn('totalbad', F.sum(F.col(true_y_col)).over(Window.patitonBy(date_col, 'model_name').orderBy(F.lit(1))))\
.withColumn('totalgood', F.sum(1-F.col(true_y_col)).over(Window.patitonBy(date_col, 'model_name').orderBy(F.lit(1))))\
.withColumn('rnk2', F.row_number().over(Window.partitionBy(date_col, 'model_name').orderBy(F.col(pred_y_col).asc())))\
.filter(F.col(true_y_col)==1)\
.groupBy(date_col, 'model_name')\
.agg(((F.sum(F.col('rnk2'))-0.5*(F.max(F.col('totalbad')))*(1+F.max(F.col('totalbad'))))/(F.max(F.col('totalbad'))*F.max(F.col('totalgood')))).alias('AUC'))\
.orderBy('model_name', date_col)
KS
KS统计量是基于经验累积分布函数(Empirical Cumulative Distribution Function,ECDF)
建立的,一般定义为:
\]
即为TPR与FPR差值绝对值的最大值。
\]
KS计算方法有很多种,这里使用的是分箱法分别计算TPR与FPR,然后得到KS。
使用PySpark计算代码如下:
from pyspark.sql import functions as F
from pyspark.sql.window import Window
true_y_col = 'y'
pred_y_col = 'pred_y'
date_col = 'day'
nBins = 10
ks_df = df.filter(F.col(true_y_col)>=0).filter(F.col(pred_y_col)>=0)\
.select(true_y_col, pred_y_col, date_col, 'model_name')\
.withColumn('Bin', F.ntile(nBins).over(Window.partitionBy(date_col, 'model_name').orderBy(pred_y_col)))\
.groupBy(date_col, 'model_name', 'Bin').agg(F.sum(true_y_col).alias('N_1'), F.sum(1-F.col(true_y_col)).alias('N-0'))\
.withColumn('ALL_1', F.sum('N_1').over(Window.partitionBy(date_col, 'model_name')))\
.withColumn('ALL_0', F.sum('N_0').over(Window.partitionBy(date_col, 'model_name')))\
.withColumn('SUM_1', F.sum('N_1').over(Window.partitionBy(date_col, 'model_name').orderBy('Bin')))\
.withColumn('ALL_0', F.sum('N_0').over(Window.partitionBy(date_col, 'model_name').orderBy('Bin')))\
.withColumn('KSn', F.expr('round(abs(SUM_1/ALL_1-SUM_0/ALL_0),6)'))\
.withColumn('KS', F.round(F.max('KSn').over(Window.partitionBy(date_col, 'model_name')),6))
ks_df = ks_df.select(date_col, 'model_name', 'KS').filter(col('KS').isNotNull()).dropDuplicates()
PSI
群体稳定性指标(Population Stability Index,PSI)是风控场景常用的验证样本在各分数段的分布与建模样本分布的稳定性。在建模中,常用来筛选特征变量、评估模型稳定性。
计算公式如下:
\]
其中\(A_i\)代表的是第i个分箱中实际分布(actual)样本占比,同理\(E_i\)代表的是第i个分箱中预期分布(excepted)样本占比
使用PySpark计算代码如下:
from pyspark.sql import functions as F
from pyspark.sql.window import Window
from pyspark.sql.functions import when
date_col = 'day'
nBins = 10
feature_list = ['fea_1', 'fea_2', 'fea_3']
df = df.withColumn('flag', when(F.col(date_col) == 'actual_date'), 0).when(F.col(date_col) == 'excepted_date').otherwise(None)
quantitles = df.filter(F.col('flag') == 0)\
.approxQuantile(feature_list, [i/nBins for i in range(1, nBins)], 0.001) # 基准样本分箱
quantitles_dict = {col: quantitles[idx] for idx, col in enumerate(feature_list)}
f_quantitles_dict = F.create_map([F.lit(x) if isinstance(x, str) else F.array(*[F.lit(xx) for xx in x]) for i in quantitles_dict.items() for x in i])
unpivotExpr = "stack(3, 'fea_1', fea_1, 'fea_2', fea_2, 'fea_3', fea_3)"
psi_df = df.filter(F.col('flag').isNotNull()).select('flag', F.expr(unpivotExpr))\
.withColumn('Bin', when(F.col('value').isNull(), 'Missing').otherwise(
when(F.col('value') < f_quantitles_dict[F.col('varname')][0], 'bin_0')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][1], 'bin_1')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][2], 'bin_2')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][3], 'bin_3')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][4], 'bin_4')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][5], 'bin_5')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][6], 'bin_6')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][7], 'bin_7')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][8], 'bin_8')
.when(F.col('value') < f_quantitles_dict[F.col('varname')][8], 'bin_9')))\
.groupBy('varname', 'Bin').agg(F.sum('flag').alias('N_1'), F.sum(1-F.col('flag')).alias('N_0'))\
.withColumn('ALL_1', F.sum('N_1').over(Window.partitionBy('varname')))\
.withColumn('ALL_0', F.sum('N_0').over(Window.partitionBy('varname')))\
.withColumn('actual', F.expr('round(N_0/ALL_0, 6)'))\
.withColumn('excepted', F.expr('round(N_1/ALL_1, 6)'))\
.withColumn('PSIn', F.expr('round((actual-excepted)*ln(actual/excepted), 6'))\
.withColumn('PSI', F.round(F.sum('PSIn').over(Window.partitionBy('varname')), 6))
Reference
使用PySpark计算AUC,KS与PSI的更多相关文章
- MATLAB画ROC曲线,及计算AUC值
根据决策值和真实标签画ROC曲线,同时计算AUC的值 步骤: 根据决策值和真实标签画ROC曲线,同时计算AUC的值: 计算算法的决策函数值deci 根据决策函数值deci对真实标签y进行降序排序,得到 ...
- python计算auc指标
1.安装scikit-learn 1.1Scikit-learn 依赖 Python (>= 2.7 or >= 3.3), NumPy (>= 1.8.2), SciPy (> ...
- pyspark计算最大值、最小值、平均值
需求:使用pyspark计算相同key的最大值.最小值.平均值 说明: 最大值和最小值好计算,直接reduceByKey后使用python内置的max.min方法 平均值计算提供两种计算方法,直接先上 ...
- Python计算AUC
AUC(Area under curve)是机器学习常用的二分类评测手段,直接含义是ROC曲线下的面积.另一种解释是:随机抽出一对样本(一个正样本,一个负样本),然后用训练得到的分类器来对这两个样本进 ...
- matlab 矢量化编程(一)—— 计算 AUC
AUC = sum( (Y(2:end)+Y(1:end-1))/2 .* (X(2:end) - X(1:end-1)) X 和 Y 均是向量: Y(2:end) - Y(1:end-1),是 Y( ...
- SQL->Python->PySpark计算KS,AUC及PSI
KS,AUC 和 PSI 是风控算法中最常计算的几个指标,本文记录了多种工具计算这些指标的方法. 生成本文的测试数据: import pandas as pd import numpy as np i ...
- 模型监控指标- 混淆矩阵、ROC曲线,AUC值,KS曲线以及KS值、PSI值,Lift图,Gain图,KT值,迁移矩阵
1. 混淆矩阵 确定截断点后,评价学习器性能 假设训练之初以及预测后,一个样本是正例还是反例是已经确定的,这个时候,样本应该有两个类别值,一个是真实的0/1,一个是预测的0/1 TP(实际为正预测为正 ...
- tensorflow添加自定义的auc计算operator
tensorflow可以很方便的添加用户自定义的operator(如果不添加也可以采用sklearn的auc计算函数或者自己写一个 但是会在python执行,这里希望在graph中也就是c++端执行这 ...
- AUC计算 - 进阶操作
首先AUC值是一个概率值,当你随机挑选一个正样本以及负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值,AUC值越大,当前分类算法越有可能将正样本排在负样本前 ...
- AUC计算 - 手把手步进操作
2017-07-10 14:38:24 理论参考: 评估分类器性能的度量,像混淆矩阵.ROC.AUC等 http://www.cnblogs.com/suanec/p/5941630.html ROC ...
随机推荐
- vue核心
VUE简介 vue--一套用于构建用户界面的渐进式JavaScript框架 vue特点 采用组件化模式--提高代码复用率--让代码更好维护 声明式编程--让编码人员无需直接操作DOM--提高开发效率 ...
- Pycharm的Available Packages为空问题
问题描述:可用软件包为空,Pycharm的Available Packages为空问题 打开软件包仓库设置画面 新建软件包仓库 输入软件包仓库 完成,可用软件包 Available Packages正 ...
- CPU后面的字母含义
M(Mobile):移动笔记本电脑标准电压,功耗小,适合笔记本,i5-4310M. U(Ultra Low Voltage):移动笔记本电脑超低电压,更小的功耗.如i5-8250U. H(Height ...
- Python3 解决pip报ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:598)
ERROR: Could not install packages due to an EnvironmentError: HTTPSConnectionPool(host='files.python ...
- C++面试八股文:C++中指针、引用、解引用和取地址有什么不同?
某日小二参加XXX科技公司的C++工程师开发岗位2面: 面试官:指针.引用.解引用和取地址是C++中的重要概念,请问它们在语法和语义上有所不同? 小二:指针是一个变量,它存储了一个内存地址. 小二:引 ...
- GitHub 的项目徽章
GitHub 项目的 README.md 中可以添加徽章(Badge)对项目进行标记和说明,这些好看的小图标不仅简洁美观,而且还包含了清晰易读的信息. GitHub 项目的徽标可以参考 https:/ ...
- k8s实战案例之部署redis单机和redis cluster
1.在k8s上部署redis单机 1.1.redis简介 redis是一款基于BSD协议,开源的非关系型数据库(nosql数据库),作者是意大利开发者Salvatore Sanfilippo在2009 ...
- Spring配置动态数据库
前言 本文主要介绍使用spring boot 配置多个数据库,即动态数据库 开始搭建 首先创建一个SpringWeb项目--dynamicdb(spring-boot2.5.7) 然后引入相关依赖lo ...
- 【Netty】一个RPC实例
Netty实现简易RPC调用 总体流程: 客户端发起rpc调用请求,封装好调用的接口名,函数名,返回类型,函数参数类型,函数参数值等属性,将消息发送给服务器. 服务器的handler解析rpc请求,调 ...
- MultiscaleResNet50:AnEfficientandAccurateApproachforIma
目录 标题:<51. Multi-scale ResNet-50: An Efficient and Accurate Approach for Image Recognition> 背景 ...