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

Python scipy 指数修正高斯分布曲线拟合问题排查与实现

问题根源

你的代码出问题有三个核心原因,根本没有完成拟合流程:

  • 导入了curve_fit但从未调用执行拟合操作,指数修正高斯分布必需的形状参数K、位置参数loc、尺度参数scale没有从数据中估计,你写的exponnorm.pdf(y,K)里K是未定义变量,运行时本身就会报错,更不可能得到正确曲线
  • exponnorm.pdf的参数传参逻辑完全错误:该方法第一个入参是需要计算概率密度的自变量坐标(也就是你直方图的bin中心x值),你传入的y是直方图的频次计数,完全不符合入参要求
  • 画直方图时默认输出的是样本频次,和概率密度函数量级差极大,就算参数传对,曲线和直方图也完全匹配不上
修正方案

直接用scipy统计分布自带的拟合方法即可,比手动调用curve_fit做最小二乘适配分布更稳定,步骤如下:

  1. 提取目标列数据后先过滤无效空值
  2. 调用exponnorm.fit()直接从原始数据估计K、loc、scale三个参数,不需要手动猜初值
  3. 画直方图时开启density=True参数,让直方图纵轴输出概率密度,和pdf计算结果的量级匹配
  4. 用拟合得到的参数计算对应x区间的pdf值,再绘图对比

修正后的可运行代码如下:

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import exponnorm

# 读取数据
data = np.genfromtxt("Data.dat", delimiter='\t')
# 提取第二列值为922的行,取第9列(索引8)的TOF数据
Tofs = data[data[:,1] == 922, 8]
# 过滤可能的nan无效值
Tofs = Tofs[~np.isnan(Tofs)]

# 画归一化直方图
plt.figure(figsize=(10,6))
counts, bin_borders, _ = plt.hist(Tofs, bins=100, density=True, alpha=0.6, label='原始数据直方图')
# 计算每个bin的中心x坐标
bin_centers = (bin_borders[:-1] + bin_borders[1:]) / 2

# 核心:从原始数据拟合exponnorm的三个参数 K, loc, scale
K_fit, loc_fit, scale_fit = exponnorm.fit(Tofs)
print(f"拟合得到参数:K={K_fit:.3f}, loc={loc_fit:.3f}, scale={scale_fit:.3f}")

# 用拟合参数计算pdf值
pdf_vals = exponnorm.pdf(bin_centers, K_fit, loc=loc_fit, scale=scale_fit)
# 画拟合曲线
plt.plot(bin_centers, pdf_vals, 'r-', linewidth=2, label='指数修正高斯拟合曲线')

plt.xlabel('TOF值')
plt.ylabel('概率密度')
plt.legend()
plt.show()
拟合优化提示
  • 如果自动拟合的效果不好,可以给fit()方法传入合理的参数初值,比如提前把loc初值设为数据的峰值位置,能大幅提升拟合收敛速度和准确率
  • 直方图的bin数量可以根据数据量调整,你当前有效数据量在400行左右,bins设为30~50比100更能降低统计噪声对拟合的干扰
  • 一般做分布参数估计优先用scipy分布自带的fit()方法,该方法基于极大似然估计做参数优化,稳定性比手动写最小二乘拟合高很多;如果确实需要拟合直方图的频次曲线,再调用curve_fit,传入归一化后的y值和合理参数初值即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:15:28