使用HiveQL计算PSI(Population Stability Index)

1.群体稳定性指标

群体稳定性指标(Population Stability Index,PSI),通常用于检验模型及数据分布的稳定性。其计算公式如下:

psi = sum((实际占比-预期占比)* ln(实际占比/预期占比))

2.HiveQL计算PSI

以下PSI计算公式主要是为了计算一些模型中的各个指标的稳定性,其主要解决了利用当天的标签分布和上一个有效日期(比如:有数据)的标签的稳定性PSI计算。

以下代码段假设psi_bin_rate_data中已经计算好了每个features的各个分箱的实际概率。该表的表结构如下:

字段名字段释义
features特征名
features_name特征中文释义
bins分箱
rate分箱占比
date_time日期

方法一:

select features,features_name,date_time,sum(psi_bins) as psi
from (select features,features_name,bins,(last_rate-rate)*ln(last_rate/rate) as psi_bins,date_time
	from (select features,features_name,bins,rate,
			lead(rate,1,0.000001)over(partition by features,features_name,bins order by date_time desc) as last_rate,
			date_time
		from psi_bins_rate_data)a
	)a
group by features,features_name,date_time

这种方法代码量最小,但是有一个缺陷。举个例子,现在feature='a01'在以下两个日期的分箱数据如下:

binsdate_time='2020-03-05'date_time='2020-03-04'
[0,2]0.50.6
[3,5]0.30.2
[6,8]0.10.2
>80.1 

如果在psi_bin_rate_data中feature='a01'没有出现date_time='2020-03-04',分箱为>8的记录的话,按照lead()函数的意义,它会一直往下寻找,假如直到date_time=‘2020-03-01’,feature='a01'才有分箱为>8的记录的话,则会把这条记录中对应的rate拿过来计算,这个时候显然就不正确了。基于此,延伸出了方法二。

方法二:

select features,features_name,date_time,sum(psi_bins) as psi
from (
	select features,features_name,bins,(last_rate-rate)*ln(last_rate/rate) as psi_bins
	from 
		(select features,features_name,bins,rate,
			first_value(rate)over(partition by feature,feature_name,bins order by rn asc range between 1 preceding and current row) as last_rate,
			date_time
		from (select *,dense_rank()over(order by date_time desc) rn 
			from psi_bins_rate_data)a
		)a
	)a
group by features,features_name,date_time

在窗口函数中使用range,可以将日期固定,但需要先对日期进行排序编码。这种方法顺利填了方法一的坑,但这种方法也不是万能的。 举个例子,现在feature='a01'在以下两个日期的分箱数据如下:

binsdate_time='2020-03-05'date_time='2020-03-04'
[0,2]0.50.6
[3,5]0.30.19
[6,8] 0.01
>80.20.3

如果在psi_bin_rate_data中feature='a01'没有出现date_time='2020-03-05',分箱为[6,8]的记录的话,使用方法二计算PSI仍然是不准确的。因为在最后求和各个bins_psi的死后, 只计算了[0,2],[3,5],>8 这三个分箱的bins_psi。所以计算出的PSI不准确。基于此,想到了方法三。

顺便,为什么方法二中的窗口函数用first_value,而不用lead,参考https://blog.csdn.net/yeshang_lady/article/details/104488404

方法三:

select features,features_name,sum(psi_bins) psi 
from (
	select features,features_name,bins,(last_rate-rate)*ln(last_rate/rate) psi_bins 
	from (
		select coalesce(x.features,y.features) features,
			coalesce(x.features_name,y.features_name) features_name, 
			coalesce(x.bins,y.bins) bins, nvl(x.rate,0.0001) rate,
			nvl(y.rate,0.0001) last_rate 
		from (select features,features_name,bins,rate 
			from (
				select *,dense_rank() over(order by date_time desc) rn 
				from psi_bins_rate_data) x 
				where rn=1
				)x 
			full outer join 
			(select features,features_name,bins,rate 
			from (
				select *,dense_rank() over(order by date_time desc) rn 
				from psi_bins_rate_data) y 
				where rn=2
				)y
			on x.features=y.features and x.bins=y.bins
		)t
	)t 
group by features,features_name 

相比前两种方法,方法三在PSI的计算上是正确的,但这种方法只能求date_time最大(或最小,dense_rank()over()改为正序排序即可)相比于前一天的PSI计算。

总结

  • 如果缺失的分箱占比通常比较小的话,这三种方法计算出来的PSI,误差在可接受的范围内。
  • 目前,我认为我在各个方法的缺陷郡来自于psi_bin_rate_data。因为在这张表中,如果某一个分箱下的rate为0,那么这个分箱是该表中是不会有记录的。而正是由于分箱数据不完备,导致计算出的PSI数据不准确。如果我们从psi_bin_rate_data 表入手,将分箱占比为0的记录也保留下来,那么计算PSI将会非常简单,直接方法一就可以解决了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值