2015-10-17 121 views
4

我想用一個常數pw擬合指數函數y=x ** pw來適應兩個數據點。 scipycurve_fit函數應優化adj1adj2。我已經嘗試了下面的代碼,但無法使其工作。曲線不通過數據點。我該如何解決它?用scipy通過兩個數據點擬合指數函數curve_fit

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() 

回答

1

這裏的解決方案。我認爲曲線擬合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() 
+0

lmfit是一個真正偉大的工具,並在幾個案件工作,在那裏SciPy的失敗(限定或限制本地解算器) – Moritz

2

如果你想從只有兩個數據點發現在你的目標函數的兩個參數,這不一定是一個問題的最小二乘法擬合:剛剛解決了聯立方程Y1 = B(X1 +一)^ p和Y2 = b(×2 +α)^ p爲參數ab

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() 

所得功能將通過這兩個點準確,當然。

enter image description here

+0

我同意。 scipy唯一的問題是你不能把函數的某些參數作爲常量來保存。 – Nickpick

2

這只是因爲圓法是殺害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() 

enter image description here