自定义函数拟合直方图时曲线平坦不匹配问题咨询
对数分箱直方图高斯拟合平坦问题修复
核心错误点
- 初始参数设置错误:初始参数
x0全部设为0,优化器从a=0的初始点迭代,会直接收敛到y=0的局部最优解,输出平坦直线 - 测试数据不符合对数坐标要求:你生成的正态分布均值为
1e-10、标准差为1e-7,近50%的样本为负值,对数坐标无法展示负数,这些样本会被错误归到边缘bin,完全破坏分布形态 - 分箱中心计算错误:对数分箱的中心不能用算术平均计算,需要用几何平均,否则x坐标位置偏移会直接导致拟合错误
- 拟合曲线采样逻辑错误:用
np.linspace在对数区间采样时,绝大多数点集中在大数值端,低数值区间采样严重不足,和对数分箱的密度不匹配 - 重复拟合无意义:第一次拟合用错误初始值得到错误结果,再把这个结果作为初始值做第二次拟合,根本无法跳出错误收敛域
- 冗余导入:代码中重复导入优化模块、导入未使用的pandas库,虽然不影响拟合结果,但属于无效代码
修正后代码
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 修正测试数据:保证所有样本为正,落在对数区间内 x = np.random.normal(5e-8, 2e-8, size=10000) x = x[x>0] # 过滤极小概率出现的负值 def func(x, a, b, c): return a * (np.exp(-b*(x-c)**2)) bins=25 logbins = np.logspace(np.log10(1.0E-10),np.log10(1E-07),bins) bin_heights, bin_borders, _ = plt.hist(x, bins=logbins, edgecolor='black', color='b') # 修正:对数分箱中心用几何平均计算 bin_centers = np.sqrt(bin_borders[:-1] * bin_borders[1:]) # 修正:传入合理初始参数,a为峰值高度、c为分布中心位置、b为宽度相关系数 x0 = np.array([bin_heights.max(), 1/(2*(2e-8)**2), 5e-8]) popt, pcov = curve_fit(func, bin_centers, bin_heights, p0=x0) # 修正:用logspace生成拟合区间点,匹配对数坐标密度 x_interval_for_fit = np.logspace(np.log10(bin_borders[0]), np.log10(bin_borders[-1]), 1000) plt.plot(x_interval_for_fit, func(x_interval_for_fit, *popt), label='Fit',color='r', linewidth=2) plt.xscale('log') plt.legend() plt.show()
补充说明
修正后拟合曲线会和对数分箱下的直方图形态完全匹配,不会再出现平坦直线的问题。如果你要拟合的原始数据确实存在负值,就不能直接用对数x轴做拟合,需要先做坐标转换或者选择适配负值的分布函数。

内容的提问来源于stack exchange,提问作者ABDUL
相关产品推荐
相关产品推荐

