【问题标题】:Fitting data with Lmfit用 Lmfit 拟合数据
【发布时间】:2018-07-31 20:00:34
【问题描述】:

我有两组数据,一组用于 x 轴,另一组用于 y 轴。

我想通过 Lmfit 使用 Lèvy 分布的以下定义来拟合这些数据。

我对 c 参数有一个约束,这意味着它必须大于零。

下面是我的代码:

import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model
from lmfit import Parameters

def Levy(x, c, m):
    sq = np.sqrt(c/(2*np.pi))
    ex = np.exp(-c/(2*(x-m)))
    den = (x-m)**(3/2)
    return (sq*(ex/den))

x =np.array([0.03,0.08,0.13,0.18,0.23,0.28,0.33,0.38,0.43,0.48,0.53,0.58,0.63,0.68,0.73,0.78,0.83,0.88,0.93,0.98,1.03,1.08,1.13,1.18,1.23,1.28,1.33,1.38,1.43,1.48,1.53,1.58,1.63,1.68,1.73,1.78,1.83,1.88,1.93,1.98,2.03,2.08,2.13,2.18,2.23,2.28,2.33,2.38,2.43,2.48,2.53,2.58,2.63,2.68,2.73,2.78,2.83,2.88,2.93,2.98,3.03,3.08,3.13,3.28,3.88])

y = np.array([0.9931429,0.98486193,0.9783219,0.96919757,0.95680234,0.93760247,0.91618782,0.89456217,0.87109068,0.85210239,0.83358852,0.81407275,0.78769989,0.769608,0.73258027,0.71332794,0.68289386,0.65704847,0.62566436,0.60256181,0.57835128,0.5548792,0.53167057,0.50746062,0.48303911,0.45002014,0.4283945,0.40618835,0.38540666,0.36984661,0.34648062,0.3311846,0.30871501,0.29568682,0.28075974,0.2635118,0.25164404,0.23793043,0.22806706,0.21794024,0.2047541,0.1938894,0.18065023,0.16651464,0.15079665,0.14093328,0.1260062,0.1199406,0.11350606,0.1043281,0.09615262,0.08565687,0.07763934,0.07194268,0.0637672,0.05701618,0.04615091,0.03945234,0.03285927,0.03238484,0.0287456,0.0242624,0.01529543,0.00986279,0.00173977])

gmodel = Model(Levy)
params = Parameters()
params.add('c', value=0.2)
params.add('m', value=0)
result3 = gmodel.fit(y, x=x, params=params)

plt.plot(x,y,'bo')
plt.plot(x, result3.best_fit)
plt.show()

我有两个问题:

  • 如何为 c 的不同值绘制拟合?

  • 即使我改变了 c 的值,Lèvy 分布的峰值也没有达到数据集图的峰值。

有人可以帮帮我吗?谢谢!

【问题讨论】:

    标签: python lmfit


    【解决方案1】:

    如果我没记错的话,Lévy 分布中的 µ 参数是位置参数,移动概率密度函数开始为非空的点。

    根据您的数据,如果 Lévy 分布可以很好地描述它,那么该参数将等于 0,因此我们只剩下一个参数,即缩放参数 c。

    似乎 Lévy 分布可能不是描述您的数据的最佳概率分布。 我重新调整了您的数据,使曲线下的面积等于 1(对于任何概率密度函数),并将其与具有各种 c 值的 Lévy 分布一起绘制,实际上似乎没有一个可以很好地描述您的数据。

    f = plt.figure()
    ax = plt.gca()
    t = np.linspace(0, 4, 500)
    for c in [0.2, 0.5, 1, 2, 4]:
        ax.plot(t, Levy(t, c, 0), label=r"$c=%s$"%c)
    
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    
    area_y = sum([(x[i+1]-x[i])*(y[i+1]+y[i])*0.5 for i in range(len(x)-1)])
    y_ = y/area_y
    ax.plot(x, y_, '.', label="data")
    
    ax.legend()
    

    如果您想将这样的函数拟合到对参数有约束的数据,您也可以使用 scipy optimize.curve_fit 函数。

    【讨论】:

    • 您好,感谢您的回答!我已经将我的数据与 scipy optimize.curve_fit 以及其他分布(如高斯和双高斯)对参数进行了拟合,但它们不能很好地拟合 x 值大于约 3 的数据。出于这个原因,我正在考虑征费分布。你能解释一下你是如何规范化数据的吗?以下两行代码我不清楚:area_y = sum([(x[i+1]-x[i])*(y[i+1]+y[i])*0.5 for i in range(len(x)-1)])y_ = y/area_y
    • 另外,在您的代码中,您不是只是绘制了几个 Levy 分布的图吗?我实际上想使用分布来适应 Lmfit。再次感谢!
    • 是的,我只是绘制了几个 Lévy 分布,以表明无法获得良好的拟合。如果您使 c 小于 0.2,则最大值会更高,但下降幅度会更大,因此不适合您的数据。如果您为 c 取更高的值,它不会更好地拟合您的数据,因此即使您使用 Lmfit 或任何拟合方法也无法获得良好的拟合。
    • 对于归一化,我通过对宽度为 x[i+1]-x[i] 且高度为 (y[i+1]+y[i] 的矩形的面积求和来计算面积])*0.5(两个 y 值之间的平均值)。然后我通过这个对所有 y 值进行归一化,使得曲线下的面积现在为 1。
    • 好的,现在更清楚了。但我仍然有一些疑问:这样做你使用的是标准化数据,但 Lèvy 函数的方程没有标准化。我错了?另外您不认为进行拟合也许我可以找到 c 参数的值,从而使拟合更接近数据吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 2016-10-01
    • 2019-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多