PSI群体稳定指数-Python实现

PSI群体稳定指数-Python实现

PSI群体稳定指数

  群体稳定性指标PSI(population stability index )用于衡量测试样本和建模样本分数间数据分布差异性,是模型稳定性的常见指标。公式如下所示:

P S I = ∑ i = 0 b i n s ( A c t u a l i − E x p e c t e d i ) × l n ( A c t u a l i E x p e c t e d i ) PSI = \sum_{i=0}^{bins}\left ( Actual_{i}-Expected_{i} \right )\times ln\left ( \frac{Actual_{i}}{Expected_{i}} \right ) PSI=i=0bins(ActualiExpectedi)×ln(ExpectediActuali)

  其中,bins是分箱数量,Actual是实际占比,Expected是预期占比。
  一般来说,PSI小于0.1模型稳定性较高,0.1至0.2之间稳定性一般,大于0.2建议重新迭代模型。

计算样例
  对比去年和今年某地区人的年龄分布的差异性,去年抽查的年龄命名为Actual,今年年龄命名为Expect,如下所示。
  Actual : 81, 48, 49, 82, 35, 6,……, 49, 69, 73, 57, 93, 77, 21
  Expect : 41, 34, 62, 81, 11, 33, ……, 21, 21, 74, 68, 62, 21, 83

  将Actual等宽分为10组,并按Actual相同的区间将Expect分组,计算结果如下:
样例
  其次,计算每个分组内占总量的占比,如下图中,第0号分组内,actual有15条数据,actual共100条数据,则对应的占比为15%。计算结果如下:
计算占比
  最后,按照公式计算得出每个组内的PSI,公式如下,将所有分组的psi求和为最终PSI值为0.184。

P S I i = ( a c t u a l _ r a t e i − e x p e c t _ r a t e i ) × l n ( a c t u a l _ r a t e i e x p e c t _ r a t e i ) PSI_{i} =\left (actual\_rate_{i}-expect\_rate_{i} \right )\times ln\left ( \frac{actual\_rate_{i}}{expect\_rate_{i}} \right ) PSIi=(actual_rateiexpect_ratei)×ln(expect_rateiactual_ratei)

  计算结果如下:
计算PSI

Python 实现

#Python代码实现
import pandas as pd
import numpy as np

def cal_psi(actual, predict, bins=10):
    """
    功能: 计算PSI值,并输出实际和预期占比分布曲线
    :param actual: Array或series,代表真实数据,如训练集模型得分
    :param predict: Array或series,代表预期数据,如测试集模型得分
    :param bins: 分段数
    :return:
        psi: float,PSI值
        psi_df:DataFrame
    
    Examples
    -----------------------------------------------------------------
    >>> import random
    >>> act = np.array([random.random() for _ in range(5000000)])
    >>> pct = np.array([random.random() for _ in range(500000)])
    >>> psi, psi_df = cal_psi(act,pct)
    >>> psi
    1.65652278590053e-05
    >>> psi_df
       actual  predict  actual_rate  predict_rate           psi
    0  498285    49612     0.099657      0.099226  1.869778e-06
    1  500639    50213     0.100128      0.100428  8.975056e-07
    2  504335    50679     0.100867      0.101360  2.401777e-06
    3  493872    49376     0.098775      0.098754  4.296694e-09
    4  500719    49710     0.100144      0.099422  5.224199e-06
    5  504588    50691     0.100918      0.101384  2.148699e-06
    6  499988    50044     0.099998      0.100090  8.497110e-08
    7  496196    49548     0.099239      0.099098  2.016157e-07
    8  498963    50107     0.099793      0.100216  1.790906e-06
    9  502415    50020     0.100483      0.100042  1.941479e-06

    """
    actual_min = actual.min()  # 实际中的最小概率
    actual_max = actual.max()  # 实际中的最大概率
    binlen = (actual_max - actual_min) / bins
    cuts = [actual_min + i * binlen for i in range(1, bins)]#设定分组
    cuts.insert(0, -float("inf"))
    cuts.append(float("inf"))
    actual_cuts = np.histogram(actual, bins=cuts)#将actual等宽分箱
    predict_cuts = np.histogram(predict, bins=cuts)#将predict按actual的分组等宽分箱
    actual_df = pd.DataFrame(actual_cuts[0],columns=['actual'])
    predict_df = pd.DataFrame(predict_cuts[0], columns=['predict'])
    psi_df = pd.merge(actual_df,predict_df,right_index=True,left_index=True)
    psi_df['actual_rate'] = (psi_df['actual'] + 1) / psi_df['actual'].sum()#计算占比,分子加1,防止计算PSI时分子分母为0
    psi_df['predict_rate'] = (psi_df['predict'] + 1) / psi_df['predict'].sum()
    psi_df['psi'] = (psi_df['actual_rate'] - psi_df['predict_rate']) * np.log(
        psi_df['actual_rate'] / psi_df['predict_rate'])
    psi = psi_df['psi'].sum()
    return psi, psi_df
  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值