如何为seaborn histplot多分布直方图的分箱概率设置权重
实现方案
不需要修改seaborn计算完成的分箱结果,直接利用histplot自带的weights参数即可实现需求。stat='probability'模式下,分箱高度的计算逻辑是:箱内样本的权重总和 / 全量样本的权重总和。只要给同一分布的所有样本分配统一权重,让每个分布的总权重等于你预设的系数,最终所有分箱的概率总和自然为1,且每个分布的总概率占比恰好等于预设系数。
具体实现代码
注意原示例代码缺少numpy导入,以下是可直接运行的完整代码:
from scipy.stats import skewnorm import seaborn as sns import pandas as pd import numpy as np import matplotlib.pyplot as plt rdata = pd.DataFrame() np.random.seed(2022) rdata['Recession'] = skewnorm.rvs(1, loc=3000, scale=400, size=100000) rdata['Recovery'] = skewnorm.rvs(0, loc=3300, scale=300, size=100000) rdata['Expansion'] = skewnorm.rvs(-1, loc=3800, scale=200, size=100000) rdata['Slowdown'] = skewnorm.rvs(-3, loc=3600, scale=250, size=100000) # 定义每个分布的目标总概率占比 weight_config = { 'Recession': 0.4, 'Recovery': 0.2, 'Expansion': 0.2, 'Slowdown': 0.2 } # 宽表转长表,方便给每个样本匹配权重 long_df = rdata.melt(var_name='economic_cycle', value_name='indicator') # 单个样本权重 = 对应分布的目标总占比 / 该分布的样本总数 long_df['sample_weight'] = long_df['economic_cycle'].map(weight_config) / long_df.groupby('economic_cycle')['indicator'].transform('count') sns.histplot( data=long_df, x='indicator', hue='economic_cycle', bins=50, stat='probability', weights='sample_weight', cumulative=False, kde=True ) plt.show()
效果说明
- 运行代码后,四个分布所有分箱的概率总和恰好为1
- Recession的全部分箱概率和为0.4,其余三个分布的分箱概率和各为0.2,完全符合加权要求
- 附带的kde曲线会自动适配样本权重,不需要额外调整
不推荐的备选方案
如果一定要在seaborn计算完分箱概率后再乘以系数,可以在绘图后遍历Axes对象的patches属性(对应每个分箱的矩形元素),识别每个矩形所属的分布后乘以对应系数,但该方法需要自行匹配分布和矩形的对应关系,且无法同步调整kde曲线,实用性很低。

内容的提问来源于stack exchange,提问作者Gerry
相关产品推荐
相关产品推荐

