You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多列Pandas DataFrame对数直方图添加均值点与标准差线?

实现方案:在对数刻度直方图的每个区间添加均值点和标准差竖线

我拥有三个包含多列的Pandas DataFrame,数据生成代码如下:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from scipy import stats
import seaborn as sns
data = np.random.randint(0, 1001, size=(1000, 100))
data[data < 0] = 0
df1 = pd.DataFrame(data)
df2 = pd.DataFrame(data)
df3 = pd.DataFrame(data)

已通过以下代码绘制出三个DataFrame的未堆叠对数刻度直方图:

num_bin = 30
figure, axes = plt.subplots(1, 3, sharex=True, figsize=(15,5))
axes[0].set_title('log df1')
axes[1].set_title('log df2')
axes[2].set_title('log df3')
sns.histplot(ax=axes[0],data=df1[df1>0], bins=num_bin, log_scale=True, weights=None, legend=False, palette='viridis', alpha=0.1)
sns.histplot(ax=axes[1],data=df2[df2>0], bins=num_bin, log_scale=True, weights=None, legend=False, palette='husl', alpha=0.1)
sns.histplot(ax=axes[2],data=df3[df3>0], bins=num_bin, log_scale=True, weights=None, legend=False, palette='inferno', alpha=0.1)
plt.show() 

现在希望在每个直方图的每个区间(bin)上,添加基于所有列计算得到的均值点和标准差竖线,请问有什么实现方案?


核心思路

  • 先统一计算所有直方图的对数刻度区间边界,确保三个子图的区间完全一致
  • 对每个DataFrame,按区间分组计算所有数据的均值和标准差
  • 在对应子图上用散点标记均值位置,用竖线表示标准差范围

完整代码实现

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns

# 生成数据
data = np.random.randint(0, 1001, size=(1000, 100))
data[data < 0] = 0
df1 = pd.DataFrame(data)
df2 = pd.DataFrame(data)
df3 = pd.DataFrame(data)

num_bin = 30
figure, axes = plt.subplots(1, 3, sharex=True, figsize=(15,5))
axes[0].set_title('log df1')
axes[1].set_title('log df2')
axes[2].set_title('log df3')

# 统一生成对数刻度区间边界(保证三个图的bins完全匹配)
all_valid_data = pd.concat([df1[df1>0].stack(), df2[df2>0].stack(), df3[df3>0].stack()])
log_bins = np.logspace(np.log10(all_valid_data.min()), np.log10(all_valid_data.max()), num_bin + 1)

# 定义工具函数:计算区间统计量并绘制到指定轴
def add_stats_markers(ax, df, bins, marker_color):
    # 展平数据并过滤0值
    flat_data = df[df>0].stack().values
    # 给每个数据点分配所属区间
    bin_indices = np.digitize(flat_data, bins)
    # 按区间分组计算均值、标准差,跳过空区间
    group_stats = pd.DataFrame({
        'value': flat_data,
        'bin_idx': bin_indices
    }).groupby('bin_idx').agg(
        mean_val=('value', 'mean'),
        std_val=('value', 'std')
    ).dropna()
    
    # 计算每个区间的中心位置(对数轴用几何平均更合理)
    bin_centers = np.sqrt(bins[:-1] * bins[1:])[group_stats.index - 1]
    
    # 绘制均值点(zorder确保在直方图上方)
    ax.scatter(bin_centers, group_stats['mean_val'], color=marker_color, s=50, zorder=5, label='均值')
    # 绘制标准差竖线
    for x, mean, std in zip(bin_centers, group_stats['mean_val'], group_stats['std_val']):
        ax.vlines(x, mean - std, mean + std, color=marker_color, alpha=0.7, zorder=4)
    ax.legend()

# 绘制直方图并添加统计标记
sns.histplot(ax=axes[0], data=df1[df1>0], bins=log_bins, log_scale=True, weights=None, legend=False, palette='viridis', alpha=0.1)
add_stats_markers(axes[0], df1, log_bins, '#440154')

sns.histplot(ax=axes[1], data=df2[df2>0], bins=log_bins, log_scale=True, weights=None, legend=False, palette='husl', alpha=0.1)
add_stats_markers(axes[1], df2, log_bins, '#fde725')

sns.histplot(ax=axes[2], data=df3[df3>0], bins=log_bins, log_scale=True, weights=None, legend=False, palette='inferno', alpha=0.1)
add_stats_markers(axes[2], df3, log_bins, '#e7298a')

plt.tight_layout()
plt.show()

关键细节说明

  • 统一区间:基于所有有效数据生成对数区间,避免三个子图的区间错位,保证统计量的可比性
  • 区间统计:用np.digitize快速分配数据区间,分组计算自动跳过无数据的空区间
  • 对数适配:区间中心采用几何平均计算,符合对数坐标轴的分布逻辑
  • 图层控制:通过zorder参数让统计标记显示在直方图上方,提升视觉可读性

内容的提问来源于stack exchange,提问作者Giantanque

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:57:50