You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Matplotlib和Numpy的数值字典分析与泊松误差传递

我来帮你一步步解决这个问题,从区间中心值的修正到泊松误差棒的计算,再到两幅图的实现,咱们逐个击破:


1. 先搞定区间中心值的计算

你之前的中心值代码失效,大概率是用了算术平均处理对数空间的区间——但np.logspace生成的是对数均匀分布的区间,算术平均会被大数值拉偏,正确的做法是用几何平均(对数中心),这样才能代表区间的典型位置:

import numpy as np
import collections
from matplotlib import pyplot as plt

# 生成区间边界
bins = np.logspace(8.20, 12.20, 11)
# 计算每个区间的几何平均中心(对数空间的中点)
bin_centers = np.sqrt(bins[:-1] * bins[1:])
# 等价写法:10 ** ((np.log10(bins[:-1]) + np.log10(bins[1:])) / 2)

这个中心值会完美贴合对数坐标轴的区间中点,解决你之前的中心值失效问题。


2. 定义核心计算函数

先把权重和平均值贡献的逻辑封装成函数,方便后续调用:

def calculate_weight(item_list):
    """根据列表元素数量返回对应权重"""
    n = len(item_list)
    if n == 3:
        return 1.0
    elif n == 2:
        return 2/3
    elif n == 1:
        return 1/3
    return 0.0  # 空列表不贡献

def calculate_avg_contribution(item_list):
    """返回列表元素的平均值,空列表返回0"""
    if not item_list:
        return 0.0
    return np.mean(item_list)

3. 计算区间统计量与双重泊松误差

这里要处理单个键的不确定性区间总和的不确定性,两者叠加得到最终的误差棒:

# 假设你的字典是 data_dict = collections.defaultdict(list)
# 初始化存储变量
fig1_weight_totals = []
fig1_weight_errors = []
fig2_avg_sums = []
fig2_avg_errors = []

# 遍历每个区间
for low, high in zip(bins[:-1], bins[1:]):
    # 筛选当前区间内的所有键
    keys_in_bin = [k for k in data_dict.keys() if low <= k < high]

    # === 图1:加权总数与误差 ===
    weights = [calculate_weight(data_dict[k]) for k in keys_in_bin]
    total_weight = sum(weights)
    fig1_weight_totals.append(total_weight)

    # 双重泊松误差计算:
    # 每个键的权重对应n/3(n是列表元素数),n的泊松误差是sqrt(n),因此权重误差为sqrt(n)/3 = sqrt(3w)/3 = sqrt(w/3)
    # 区间总和的误差是各键误差的平方和开根号(独立误差方差相加)
    weight_errors = [np.sqrt(len(data_dict[k])) / 3 for k in keys_in_bin]
    total_weight_error = np.sqrt(sum([e**2 for e in weight_errors]))
    fig1_weight_errors.append(total_weight_error)

    # === 图2:平均值之和与误差 ===
    avg_contribs = [calculate_avg_contribution(data_dict[k]) for k in keys_in_bin]
    total_avg = sum(avg_contribs)
    fig2_avg_sums.append(total_avg)

    # 平均值的误差是样本标准误(std/sqrt(n)),区间总和误差同样是各标准误的平方和开根号
    avg_errors = []
    for k in keys_in_bin:
        lst = data_dict[k]
        n = len(lst)
        if n == 0:
            avg_errors.append(0.0)
            continue
        sample_std = np.std(lst, ddof=1)  # 样本标准差
        standard_error = sample_std / np.sqrt(n)
        avg_errors.append(standard_error)
    total_avg_error = np.sqrt(sum([e**2 for e in avg_errors]))
    fig2_avg_errors.append(total_avg_error)

# 图2归一化到总和为1,误差同步按比例缩放
total_fig2_sum = sum(fig2_avg_sums)
fig2_avg_normalized = [x / total_fig2_sum for x in fig2_avg_sums]
fig2_errors_normalized = [e / total_fig2_sum for e in fig2_avg_errors]

4. 绘制两幅带误差棒的图

最后用plt.errorbar绘制带泊松误差棒的图,注意x轴用对数刻度:

图1:区间加权总数

plt.figure(figsize=(10, 5))
plt.errorbar(bin_centers, fig1_weight_totals, yerr=fig1_weight_errors, 
             fmt='o-', capsize=5, color='tab:blue')
plt.xscale('log')
plt.xlabel('Key Value (Log Scale)')
plt.ylabel('Weighted Total')
plt.title('Weighted Count per Log-Space Interval')
plt.grid(True, which='both', linestyle='--', alpha=0.7)
plt.show()

图2:归一化平均值之和

plt.figure(figsize=(10, 5))
plt.errorbar(bin_centers, fig2_avg_normalized, yerr=fig2_errors_normalized, 
             fmt='s-', capsize=5, color='tab:orange')
plt.xscale('log')
plt.xlabel('Key Value (Log Scale)')
plt.ylabel('Normalized Average Sum')
plt.title('Normalized Average Contribution per Log-Space Interval')
plt.grid(True, which='both', linestyle='--', alpha=0.7)
plt.ylim(0, max(fig2_avg_normalized) + max(fig2_errors_normalized)*1.2)  # 优化y轴范围
plt.show()

关键问题说明

  1. 为什么用几何平均做中心值?
    因为你的区间是对数均匀分布的,算术平均会偏向大数值,几何平均(对数中点)才是区间的真实“中心”,能让x轴的点完美对应区间的中间位置。

  2. 双重泊松误差怎么理解?

    • 单个键的误差:列表元素数n本身服从泊松分布,误差为sqrt(n),权重/平均值的误差由此推导而来;
    • 区间总和的误差:多个独立误差的方差相加,再开根号得到总误差,这是统计上合并独立不确定性的标准方法。

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

火山引擎 最新活动