【问题标题】:Fixing fit parameters in curve_fit修复curve_fit中的拟合参数
【发布时间】:2017-12-21 12:18:16
【问题描述】:

我有一个函数Imaginary,它描述了一个物理过程,我想将它拟合到一个数据集x_interpolate, y_interpolate。该函数是洛伦兹峰值函数的一种形式,我有一些用户给定的初始值,除了f_peak(峰值位置),​​我使用峰值查找算法找到。除偏移量外,所有拟合参数都应为正值,因此我已相应地设置了bounds_I

def Imaginary(freq, alpha, res, Ms, off):
    numerator = (2*alpha*freq*res**2)
    denominator = (4*(alpha*res*freq)**2) + (res**2 - freq**2)**2
    Im = Ms*(numerator/denominator) + off
    return Im

pI = np.array([alpha_init, f_peak, Ms_init, 0])

bounds_I = ([0,0,0,0, -np.inf], [np.inf,np.inf,np.inf, np.inf])

poptI, pcovI = curve_fit(Imaginary, x_interpolate, y_interpolate, pI, bounds=bounds_I)

在某些情况下,我想在拟合过程中保持参数f_peak 不变。我尝试了一个简单的解决方案,将bounds_I 更改为:

bounds_I = ([0,f_peak+0.001,0,0, -np.inf], [np.inf,f_peak-0.001,np.inf, np.inf])

由于许多原因,这不是最佳的执行方式,所以我想知道是否有更 Pythonic 的方式来执行此操作?谢谢你的帮助

【问题讨论】:

    标签: python scipy curve-fitting


    【解决方案1】:

    如果一个参数是固定的,它就不是一个真正的参数,所以它应该从参数列表中删除。定义一个模型,将该参数替换为固定值,并对其进行拟合。下面的例子,为了简洁和独立而简化:

    x = np.arange(10)
    y = np.sqrt(x)    
    def parabola(x, a, b, c):
      return a*x**2 + b*x + c
    
    fit1 = curve_fit(parabola, x, y)  #  [-0.02989396,  0.56204598,  0.25337086]
    b_fixed = 0.5
    fit2 = curve_fit(lambda x, a, c: parabola(x, a, b_fixed, c), x, y) 
    

    第二次调用 fit 返回 [-0.02350478, 0.35048631],这是 a 和 c 的最优值。 b 的值固定为 0.5。

    当然,参数应该从初始向量 pI 和边界中删除。

    【讨论】:

      【解决方案2】:

      您可能会发现 lmfit (https://lmfit.github.io/lmfit-py/) 很有帮助。该库为 scipy 优化例程添加了更高级别的接口,旨在提供更 Pythonic 的优化和曲线拟合方法。例如,它使用 Parameter 对象来允许设置边界和固定参数,而无需修改目标或模型函数。对于曲线拟合,它定义了可以使用的高级模型函数。

      例如,您可以使用您编写的 Imaginary 函数

      from lmfit import Model
      lmodel = Model(Imaginary)
      

      然后创建Parameters(lmfit会根据你的函数签名命名Parameter对象),提供初始值:

      params = lmodel.make_params(alpha=alpha_init, res=f_peak, Ms=Ms_init, off=0)
      

      默认情况下,所有参数都是未绑定的,并且会因拟合而异,但您可以修改这些属性(无需重写模型函数):

      params['alpha'].min = 0
      params['res'].min = 0
      params['Ms'].min = 0
      

      您可以将一个(或多个)参数设置为不适应变化:

      params['res'].vary = False
      

      要明确:这不需要改变模型函数,更容易改变是固定的,可能会施加什么界限等等。

      然后您将使用模型和这些参数执行拟合:

      result = lmodel.fit(y_interpolate, params, freq=x_interpolate)
      

      您可以通过

      获得有关参数的拟合统计量、最佳拟合值和不确定性的报告
      print(result.fit_report())
      

      最适合的参数将保存在result.params

      FWIW,lmfit 还具有许多常见形式的内置模型,包括 Lorentzian 和 Constant offset。因此,您可以将此模型构建为

      from lmfit.models import LorentzianModel, ConstantModel
      
      mymodel = LorentzianModel(prefix='l_') + ConstantModel()
      
      params = mymodel.make_params()
      

      其中的参数名为 l_amplitudel_centerl_sigmac(其中 c 是常数),模型将使用名称 x 作为自变量(您的 @ 987654337@)。当您可能想要更改峰或背景的函数形式,或者将多个峰拟合到光谱时,这种方法会变得非常方便。

      【讨论】:

        猜你喜欢
        • 2012-06-07
        • 1970-01-01
        • 2019-02-12
        • 2012-11-02
        • 2018-10-21
        • 2020-05-18
        • 1970-01-01
        • 2014-01-13
        • 2020-05-05
        相关资源
        最近更新 更多