如何让Plotly Express多分组直方图的概率密度总和为1?
Plotly Express多分组直方图概率密度总面积归一为1的实现方案
问题场景
给定示例数据集:
import pandas as pd toy_df = pd.DataFrame({"value": [1, 12, 16, 4, 27, 38, 19], "group": [1, 1, 2, 1, 2, 2, 2]})
单分组时,使用px.histogram的histnorm='probability density'参数可生成总面积为1的直方图:
import plotly.express as px px.histogram(toy_df, x="value", histnorm='probability density')
但添加color="group"分组后,Plotly会对每个分组单独归一概率密度,导致所有分组的总面积之和大于1。以下是两种在Plotly生态内的实现方案:
方案一:手动计算概率密度并使用Graph Objects构建
先获取全局分箱信息,再按分组计算基于全局总样本的概率密度,最后用plotly.graph_objects绘制:
import pandas as pd import plotly.express as px import plotly.graph_objects as go import numpy as np toy_df = pd.DataFrame({"value": [1, 12, 16, 4, 27, 38, 19], "group": [1, 1, 2, 1, 2, 2, 2]}) # 获取全局分箱边界与宽度 fig_single = px.histogram(toy_df, x="value", histnorm='probability density') bin_edges = fig_single.data[0].x bin_width = bin_edges[1] - bin_edges[0] total_samples = len(toy_df) # 按分组统计各分箱样本数 grouped_counts = toy_df.groupby('group')['value'].apply( lambda x: np.histogram(x, bins=bin_edges)[0] ).unstack() # 计算基于全局总样本的概率密度 prob_density = grouped_counts / (total_samples * bin_width) # 构建直方图 fig = go.Figure() for group in prob_density.index: fig.add_trace(go.Histogram( x=toy_df[toy_df['group'] == group]['value'], name=f'Group {group}', autobinx=False, xbins=dict(start=bin_edges[0], end=bin_edges[-1], size=bin_width), y=prob_density.loc[group].values )) fig.update_layout(title='多分组概率密度直方图(总面积为1)', xaxis_title='value', yaxis_title='Probability Density') fig.show()
方案二:利用样本权重实现(更简洁)
给每个样本赋予分组占总样本的比例作为权重,结合histnorm='probability density'参数,自动实现总面积归一为1:
import pandas as pd import plotly.express as px toy_df = pd.DataFrame({"value": [1, 12, 16, 4, 27, 38, 19], "group": [1, 1, 2, 1, 2, 2, 2]}) # 计算每个分组的样本占比作为权重 group_ratios = toy_df['group'].value_counts(normalize=True) toy_df['weight'] = toy_df['group'].map(group_ratios) # 带权重绘制直方图 fig = px.histogram(toy_df, x="value", color="group", histnorm='probability density', weights='weight') fig.update_layout(title='多分组概率密度直方图(总面积为1)', xaxis_title='value', yaxis_title='Probability Density') fig.show()
原理说明
方案二的核心逻辑是:每个分组的概率密度原本基于自身样本数归一,乘以分组占总样本的比例后,所有分组的面积总和等价于基于全局样本数归一的结果,最终总面积为1。
内容的提问来源于stack exchange,提问作者Janek Ziobro
相关产品推荐
相关产品推荐

