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

如何在对数X轴直方图上正确拟合与缩放概率密度函数?

问题解决:对数轴下Gilbrat PDF拟合曲线平缓的问题

问题描述

我尝试将Gilbrat PDF拟合至列表形式的数据集,希望在对数X轴的直方图中展示数据并添加拟合曲线,但曲线相比直方图过于平缓。我曾参考相关方法调整PDF缩放,但问题仍未解决。以下是含随机生成数据的代码示例:

import scipy.stats as st
import numpy as np
import matplotlib.pyplot as plt

#create random dataset
data = st.gilbrat.rvs(scale = 10,  size = 100).tolist()

param = st.gilbrat.fit(data)
x = np.linspace(min(data),max(data),len(data))
pdf = st.gilbrat.pdf(x, param[0], param[1])

plt.figure()    
logbins = np.logspace(np.log10(np.min(data)),np.log10(np.max(data)),20)
result = plt.hist(data, bins=logbins, edgecolor="black",  alpha = 0.5, label="data")
dx = result[1][1] - result[1][0]
plt.plot(x,pdf * (len(data)*dx), label="fit")
plt.xscale('log')
plt.xlabel("x")
plt.ylabel("Number of occurence")
plt.legend()

问题根源

你用了固定的dx = result[1][1] - result[1][0]来缩放PDF,但对数刻度下的bin宽度是不均匀的——后面的bin宽度远大于前面的,单一的dx无法匹配所有位置的缩放需求,导致曲线整体被低估,看起来过于平缓。


修正方案

有两种常用的修正方式,根据你需要的y轴类型选择:

方式1:使用概率密度匹配(推荐)

让直方图输出概率密度(density=True),直接和scipy.stats的PDF输出对齐,无需额外缩放:

import scipy.stats as st
import numpy as np
import matplotlib.pyplot as plt

# 创建随机数据集
data = st.gilbrat.rvs(scale=10, size=100).tolist()

param = st.gilbrat.fit(data)
# 用对数间隔生成x点,贴合对数轴的分布,曲线更平滑
x = np.logspace(np.log10(np.min(data)), np.log10(np.max(data)), 1000)
pdf = st.gilbrat.pdf(x, param[0], param[1])

plt.figure()    
logbins = np.logspace(np.log10(np.min(data)), np.log10(np.max(data)), 20)
# 开启density=True,直方图y轴为概率密度
plt.hist(data, bins=logbins, edgecolor="black", alpha=0.5, label="data", density=True)
# 直接绘制PDF,和直方图的概率密度轴匹配
plt.plot(x, pdf, label="fit", linewidth=2)

plt.xscale('log')
plt.xlabel("x")
plt.ylabel("概率密度")
plt.legend()
plt.show()

方式2:保留出现次数作为y轴

如果需要y轴显示实际计数,需要为每个x位置匹配对应的bin宽度,再进行缩放:

import scipy.stats as st
import numpy as np
import matplotlib.pyplot as plt

# 创建随机数据集
data = st.gilbrat.rvs(scale=10, size=100).tolist()

param = st.gilbrat.fit(data)
# 用对数间隔生成x点
x = np.logspace(np.log10(np.min(data)), np.log10(np.max(data)), 1000)
pdf = st.gilbrat.pdf(x, param[0], param[1])

plt.figure()    
logbins = np.logspace(np.log10(np.min(data)), np.log10(np.max(data)), 20)
# 获取每个bin的宽度
bin_widths = logbins[1:] - logbins[:-1]
# 绘制直方图并获取计数
counts, _, patches = plt.hist(data, bins=logbins, edgecolor="black", alpha=0.5, label="data")

# 为每个x点插值匹配对应的bin宽度
x_bin_widths = np.interp(x, logbins[:-1], bin_widths)
# 缩放PDF:概率密度 * 样本数 * 对应bin宽度 = 计数
plt.plot(x, pdf * len(data) * x_bin_widths, label="fit", linewidth=2)

plt.xscale('log')
plt.xlabel("x")
plt.ylabel("出现次数")
plt.legend()
plt.show()

额外优化点

  • 用np.logspace生成x轴数据,让点在对数轴上均匀分布,拟合曲线更平滑准确
  • 增加拟合曲线的线宽(linewidth=2),让曲线更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 22:01:18