【问题标题】:Fitting exponential function through two data points with scipy curve_fit使用 scipy curve_fit 通过两个数据点拟合指数函数
【发布时间】:2016-01-16 03:59:42
【问题描述】:

我想用常数 pw 拟合指数函数 y=x ** pw 以适应两个数据点。 scipy curve_fit 函数应该优化 adj1 和 adj2。我已经尝试使用下面的代码,但无法让它工作。曲线不通过数据点。我该如何解决?

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def func(x, adj1,adj2):
    return np.round(((x+adj1) ** pw) * adj2, 2)

x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
y = [0.02,4]

pw=15
popt, pcov = curve_fit(func, x, y)

xf=np.linspace(0,1,50)

plt.figure()
plt.plot(x, y, 'ko', label="Original Data")
plt.plot(xf, func(xf, *popt), 'r-', label="Fitted Curve")
plt.show()

【问题讨论】:

    标签: python scipy curve-fitting


    【解决方案1】:

    只是因为round方法正在扼杀curve_fit搜索空间的能力。 p0 的小扰动总是会产生相同的结果,因此它会立即停止搜索,并且总是会返回您给它的任何内容作为起点(默认情况下 p0 = [1.,1.])。解决方案是简单地从您的函数中删除 np.round。

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    
    def func(x, adj1,adj2):
        return ((x+adj1) ** pw) * adj2
    
    x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
    y = [0.02,4]
    
    pw=15
    popt, pcov = curve_fit(func, x, y)
    
    xf=np.linspace(0,1,50)
    
    plt.figure()
    plt.plot(x, y, 'ko', label="Original Data")
    plt.plot(xf, func(xf, *popt), 'r-', label="Fitted Curve")
    plt.show()
    

    【讨论】:

      【解决方案2】:

      如果您只想从两个数据点找到目标函数中的两个参数,这不一定是最小二乘拟合的问题:只需求解联立方程 y1 = b(x1+a)^p 和y2 = b(x2+a)^p 对于参数a 和b:

      import numpy as np
      import matplotlib.pyplot as plt
      
      def func(x, adj1,adj2):
          return ((x+adj1) ** pw) * adj2
      
      x = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
      y = [0.02,4]
      
      pw = 15
      A = np.exp(np.log(y[0]/y[1])/pw)
      a = (x[0] - x[1]*A)/(A-1)
      b = y[0]/(x[0]+a)**pw
      
      xf=np.linspace(0,1,50)
      plt.figure()
      plt.plot(x, y, 'ko', label="Original Data")
      plt.plot(xf, func(xf, a, b), 'r-', label="Fitted Curve")
      plt.show()
      

      生成的函数当然会准确地通过这两个点。

      【讨论】:

      • 我同意。 scipy 唯一的问题是你不能将函数的某些参数保存为常量。
      【解决方案3】:

      解决方案在这里。我认为对于曲线拟合,lmfit 是 scipy 的一个很好的替代品。

      from lmfit import minimize, Parameters, Parameter, report_fit
      import numpy as np
      
      # create data to be fitted
      xf = [0.5,0.85] # two given datapoints to which the exponential function with power pw should fit
      yf = [0.02,4]
      
      # define objective function: returns the array to be minimized
      def fcn2min(params, x, data):
          pw = params['pw'].value
          adj1 = params['adj1'].value
          adj2 = params['adj2'].value
      
          model = adj1 * np.power(x + adj2, pw)
          return model - data
      
      pw=2
      
      # create a set of Parameters
      params = Parameters()
      params.add('pw',   value= pw, vary=False)
      params.add('adj1', value= 1)
      params.add('adj2', value= 1)
      
      
      # do fit, here with leastsq model
      result = minimize(fcn2min, params, args=(xf, yf))
      
      # calculate final result
      final = yf + result.residual
      
      # write error report
      report_fit(result.params)
      adj1=result.params['adj1']
      adj2=result.params['adj2']
      
      # try to plot results
      x = np.linspace(0, 1, 100)
      y = adj1 * np.power(x + adj2, pw)
      
      import pylab
      pylab.plot(xf, yf, 'ko')
      pylab.plot(x, y, 'r')
      pylab.show()
      

      【讨论】:

      • lmfit 是一个非常棒的工具,可以在 scipy 失败的几种情况下工作(有界或约束本地求解器)
      猜你喜欢
      • 2016-09-16
      • 2012-11-02
      • 1970-01-01
      • 2017-04-11
      • 2017-07-13
      • 2017-03-17
      • 2012-06-07
      • 2020-05-05
      • 1970-01-01
      相关资源
      最近更新 更多