Python如何无需手动计算简便绘制多组相对频率直方图
多组相对频率直方图实现方案
绘制多组相对频率直方图(要求分箱的频数总和为1,而非分箱面积总和为1)的实际实现比预想复杂,目前试了两种方案都有明显短板:
- 方法A:通过
weights参数可以输出正确结果,但参数逻辑不直观
实现代码:
运行效果:import numpy as np import pandas as pd import matplotlib.pyplot as plt df_a = pd.DataFrame(np.random.randn(1000),columns=['a']) df_b = pd.DataFrame(1+ np.random.randn(100),columns=['b']) # Method A ax = df_a.plot(kind='hist', weights= np.ones_like(df_a) / len(df_a),alpha=0.5) df_b.plot(kind='hist', weights= np.ones_like(df_b) / len(df_b),alpha=0.5 ,ax= ax ) plt.title("Method A") plt.show()
- 方法B:手动通过
count/sum(count)计算相对频率,逻辑好懂,但输出图表美观度差,还容易出现分箱错位问题
实现代码:
运行效果:# Method B count_a,bins_a = np.histogram(df_a.a) count_b,bins_b = np.histogram(df_b.b) plt.bar(bins_a[:-1],count_a/sum(count_a),alpha=0.5 ) plt.bar(bins_b[:-1],count_b/sum(count_b),alpha=0.5 ) plt.title("Method B")
是否存在其他实现方案,无需手动完成计算步骤,即可直接基于原始数据生成符合要求的美观相对频率直方图?
更优实现方案
直接用seaborn的histplot接口即可,不需要手动做权重计算、频数归一,指定参数就能生成样式统一美观的符合要求的图表,代码示例:
import seaborn as sns import matplotlib.pyplot as plt import pandas as pd import numpy as np # 构造示例数据集 df_a = pd.DataFrame({'value': np.random.randn(1000), 'category': 'a'}) df_b = pd.DataFrame({'value': 1 + np.random.randn(100), 'category': 'b'}) df_all = pd.concat([df_a, df_b]) # 核心参数stat='probability' 对应分箱频数总和为1的相对频率要求 sns.histplot( data=df_all, x='value', hue='category', stat='probability', alpha=0.5 ) plt.title("Seaborn 实现效果") plt.show()
这个方案的优点:
- 所有归一化计算由接口内部完成,不需要手动写权重、算占比,代码简洁
- 默认样式经过优化,自动对齐多组数据的分箱、自动生成图例,不会出现手动用
plt.bar时的柱形错位、样式粗糙问题 - 参数语义清晰,
stat='probability'直接对应需求,比传入weights参数的隐式逻辑好理解很多 - 支持灵活调整分箱数量、柱形样式、配色等参数,自定义成本低
如果不想引入seaborn依赖,pandas 1.4.0以上版本的plot.hist接口也支持stat参数,直接传stat='probability'就能实现同样效果,不需要手动传weights:
# pandas 高版本原生实现 ax = df_a['a'].plot(kind='hist', stat='probability', alpha=0.5) df_b['b'].plot(kind='hist', stat='probability', alpha=0.5, ax=ax) plt.title("Pandas 高版本实现") plt.show()
内容的提问来源于stack exchange,提问作者masaya
相关产品推荐
相关产品推荐

