Python实战:5分钟搞定PSI指标计算(附完整代码与可视化)
Python实战5分钟搞定PSI指标计算附完整代码与可视化在数据分析和风控建模中我们经常需要评估模型或特征的稳定性。想象一下这样的场景你花费数周开发的信用评分模型在上线后效果逐渐下降却找不到明确原因。这时一个名为PSIPopulation Stability Index的指标就能帮你快速定位问题所在。1. PSI指标的核心原理与应用场景PSI衡量的是两个群体在某个特征分布上的差异程度。它的数学表达式看似简单却蕴含深意PSI Σ(实际占比 - 预期占比) * ln(实际占比/预期占比)这个公式本质上是在计算两个概率分布之间的相对熵Kullback-Leibler散度。当两个分布完全相同时PSI值为0差异越大PSI值越高。典型应用场景包括模型监控比较训练集与线上数据的分数分布特征稳定性评估分析变量在不同时间段的分布变化策略效果追踪对比策略调整前后的用户群体差异提示PSI计算结果通常这样解读0.1表示稳定0.1-0.2需关注0.2可能存在严重偏移2. 快速实现PSI计算的Python方案下面这个函数封装了PSI计算的核心逻辑支持自动分箱和空值处理import numpy as np import pandas as pd def calculate_psi(actual, expected, bins10, epsilon1e-6): 计算群体稳定性指标PSI :param actual: 实际分布数组 :param expected: 预期分布数组 :param bins: 分箱数量 :param epsilon: 平滑系数避免除零错误 :return: psi值, 分箱统计DataFrame # 确定分箱边界 min_val min(np.min(actual), np.min(expected)) max_val max(np.max(actual), np.max(expected)) bin_edges np.linspace(min_val, max_val, bins1) # 计算分箱占比 actual_hist, _ np.histogram(actual, binsbin_edges) expected_hist, _ np.histogram(expected, binsbin_edges) # 添加平滑项并计算占比 actual_perc (actual_hist epsilon) / np.sum(actual_hist epsilon) expected_perc (expected_hist epsilon) / np.sum(expected_hist epsilon) # 计算各分箱PSI并求和 psi_values (actual_perc - expected_perc) * np.log(actual_perc/expected_perc) psi_total np.sum(psi_values) # 构建结果DataFrame result_df pd.DataFrame({ bin_range: [f{bin_edges[i]:.2f}-{bin_edges[i1]:.2f} for i in range(bins)], actual_count: actual_hist, expected_count: expected_hist, actual_perc: actual_perc, expected_perc: expected_perc, psi_contribution: psi_values }) return psi_total, result_df关键参数说明bins推荐10-20个分箱连续变量用等宽分箱分类变量按类别分组epsilon防止零除错误的小常数通常取1e-6到1e-43. 实战案例信用卡评分模型监控假设我们有一个信用卡评分模型需要监控2023年1月基准月和2月监控月的分数分布变化# 生成模拟数据 np.random.seed(42) base_scores np.random.normal(loc650, scale50, size10000) monitor_scores np.random.normal(loc670, scale60, size9500) # 计算PSI psi_value, psi_df calculate_psi(monitor_scores, base_scores) print(fPSI值: {psi_value:.4f}) print(分箱统计详情:) print(psi_df.head())输出结果示例bin_rangeactual_countexpected_countactual_percexpected_percpsi_contribution452.48-497.2823120.00240.00120.0015497.28-542.08158980.01660.00980.0062542.08-586.8811986820.12610.06820.0503586.88-631.68342124190.36010.24190.0987631.68-676.48312538210.32890.38210.0149PSI值: 0.1864表明存在中等程度分布偏移4. 可视化分析分布对比与PSI贡献数据可视化能更直观地展示分布差异import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) # 分布对比图 plt.subplot(1, 2, 1) plt.hist(base_scores, bins30, alpha0.5, label基准月) plt.hist(monitor_scores, bins30, alpha0.5, label监控月) plt.title(分数分布对比) plt.xlabel(信用分数) plt.ylabel(频数) plt.legend() # PSI贡献度分析 plt.subplot(1, 2, 2) plt.bar(psi_df[bin_range], psi_df[psi_contribution]) plt.title(各分箱PSI贡献度) plt.xlabel(分数区间) plt.ylabel(PSI贡献) plt.xticks(rotation45) plt.tight_layout() plt.show()可视化输出包含两个关键信息左右对比显示监控月分数整体右移均值升高586-631分区间贡献了最大的PSI值是需要重点关注的分数段5. 高级技巧与注意事项分箱策略优化等频分箱pd.qcut()确保每个分箱样本量相近自定义分箱对业务关键阈值单独设箱如拒绝分数线# 等频分箱示例 bin_edges pd.qcut(np.concatenate([base_scores, monitor_scores]), q10, duplicatesdrop).categories.values.right bin_edges np.insert(bin_edges, 0, -np.inf)缺失值处理方案单独设立缺失分箱填充后参与计算需在报告中注明剔除缺失值可能引入偏差常见踩坑点样本量过少导致分箱不稳定建议每个分箱至少50-100个样本极端值影响分箱效果可先进行Winsorize处理周期性变化误判为不稳定如季节性波动# 极端值处理示例 def winsorize(s, limits[0.01, 0.99]): return s.clip(lowers.quantile(limits[0]), uppers.quantile(limits[1])) base_scores_win winsorize(pd.Series(base_scores))对于需要高频监控的场景可以扩展以下功能自动化PSI计算流水线历史PSI趋势仪表盘基于PSI的自动预警机制在实际风控项目中我们通常会同时监控多个维度模型总分PSI关键变量PSI如收入、负债率等不同客群分层的PSI如新老客户通过这样多维度的监控体系可以快速定位模型性能波动的具体原因为模型迭代优化提供明确方向。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2436035.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!