![3fcef6e21e9cc2fd2a27b2567a8252ec.png](https://img-blog.csdnimg.cn/img_convert/3fcef6e21e9cc2fd2a27b2567a8252ec.png)
PSI计算 python实现
上次我们讲到用python实现psi的计算。本文是PSI系列的最后一篇文章,主要讲计算模型分的PSI,连续以及离散特征的PSI,以及用hive实现PSI的计算,最后会在kaggle上给出一个简单的实例。那我们开始吧~
PSI计算python实现如下:
def psi_calc(actual,predict,bins=10):
'''
功能: 计算PSI值,并输出实际和预期占比分布曲线
输入值:
actual: 一维数组或series,代表训练集模型得分
predict: 一维数组或series,代表测试集模型得分
bins: 违约率段划分个数
输出值:
字典,键值关系为{'psi': PSI值,'psi_fig': 实际和预期占比分布曲线}
'''
psi_dict = {}
actual = np.sort(actual)
predict = np.sort(predict)
actual_len = len(actual)
predict_len = len(predict)
psi_cut = []
actual_bins = []
predict_bins = []
actual_min = actual.min()
actual_max = actual.max()
cuts = []
binlen = (actual_max-actual_min) / bins
for i in range(1, bins):
cuts.append(actual_min+i*binlen)
for i in range(1, (bins+1)):
if i == 1:
lowercut = float('-Inf')
uppercut = cuts[i-1]
elif i == bins:
lowercut = cuts[i-2]
uppercut = float('Inf')
else:
lowercut = cuts[i-2]
uppercut = cuts[i-1]
actual_cnt = ((actual >= lowercut) & (actual < uppercut)).sum()+1
predict_cnt = ((predict >= lowercut) & (predict < uppercut)).sum()+1
actual_pct = (actual_cnt+0.0) / actual_len
predict_pct = (predict_cnt+0.0) / predict_len
psi_cut.append((actual_pct-predict_pct) * math.log(actual_pct/predict_pct))
actual_bins.append(actual_pct)
predict_bins.append(predict_pct)
psi = sum(psi_cut)
nbins = len(actual_bins)
xlab = np.arange(1, nbins+1)
fig = plt.figure()
plt.plot(xlab, np.array(actual_bins),'r',label='actual')
plt.plot(xlab, np.array(predict_bins),'b',label='predict')
plt.legend(loc='best')
plt.title('Psi Curve')
plt.close()
psi_dict['psi'] = psi
psi_dict['psi_fig'] = fig
return psi_dict
上述计算代码中,我们对变量的分箱采用最简单的无监督的等距的分箱方法,这个在PSI最原始的定义中也是这么定义的。
后面我们会介绍多种分箱方法,都可以来代替本代码中的分箱代码,进而得到不同分箱下的PSI。
特征PSI计算 python实现
上述代码一般用于计算模型分的PSI,有一个前提假设,就是我们的变量是连续的,如果我们要用来计算的PSI的特征离散且本身的离散值个数就小于分bin数,为了解决这样的情况,我们重写了上面的代码来计算不同类型特征的PSI,代码如下:
def fea_psi_calc(actual,predict,bins=10):
'''
功能: 计算连续变量和离散变量的PSI值
输入值:
actual: 一维数组或series,代表训练集中的变量
predict: 一维数组或series,代表测试集中的变量
bins: 违约率段划分个数
输出值:
字典,键值关系为{'psi': PSI值,'psi_fig': 实际和预期占比分布曲线}
'''
psi_dict = {}
actual = np.sort(actual)
actual_distinct = np.sort(list(set(actual)))
predict = np.sort(predict)
predict_distinct = np.sort(list(set(predict)))
actual_len = len(actual)
actual_distinct_len = len(actual_distinct)
predict_len = len(predict)
predict_distinct_len = len(predict_distinct)
psi_cut = []
actual_bins = []
predict_bins = []
actual_min = actual.min()
actual_max = actual.max()
cuts = []
binlen = (actual_max-actual_min) / bins
if (actual_distinct_len<bins):
for i in actual_distinct:
cuts.append(i)
for i in range(2, (actual_distinct_len+1)):
if i == bins:
lowercut = cuts[i-2]