2017-05-27 53 views
4

現在幾個小時,我一直試圖將模型擬合到(生成的)數據集,作爲我一直在努力解決的問題的一個原因。我爲函數f(x)= A * cos^n(x)+ b生成了數據點,並添加了一些噪聲。當我嘗試使用此功能,並curve_fit以適應數據集,我得到的錯誤Scipy.optimize.curve_fit不適合餘弦冪律

./tester.py:10: RuntimeWarning: invalid value encountered in power 
return Amp*(np.cos(x))**n + b 
/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py:690: OptimizeWarning: Covariance of the parameters could not be estimated category=OptimizeWarning) 

我使用生成的數據點和擬合模型的代碼如下:

#!/usr/bin/env python 

from __future__ import print_function 
import numpy as np 
from scipy.optimize import curve_fit 
from matplotlib.pyplot import figure, show, rc, plot 

def f(x, Amp, n, b): 

    return np.real(Amp*(np.cos(x))**n + b) 

x = np.arange(0, 6.28, 0.01) 
randomPart = np.random.rand(len(x))-0.5 
fig = figure() 
sample = f(x, 5, 2, 5)+randomPart 
frame = fig.add_subplot(1,1,1) 

frame.plot(x, sample, label="Sample measurements") 

popt, pcov = curve_fit(f, x, sample, p0=(1,1,1)) 

modeldata = f(x, popt[0], popt[1], popt[2]) 
print(modeldata) 
frame.plot(x, modeldata, label="Best fit") 

frame.legend() 
frame.set_xlabel("x") 
frame.set_ylabel("y") 

show() 

的顯示嘈雜的數據 - 請參閱下圖。

No fit is possible

請問你們有什麼事情的線索?我懷疑這與進入複雜領域的權力法律有關,因爲該職能的實際部分是nowhere divergent。我已經試過只返回函數的實際部分,在curve_fit中設置逼真的邊界,並且使用numpy數組而不是python列表作爲p0。我正在運行最新版本的scipy,scipy 0.17.0-1。

回答

6

的問題如下:

>>> (-2)**1.1 
(-2.0386342710747223-0.6623924280875919j) 
>>> np.array(-2)**1.1 
__main__:1: RuntimeWarning: invalid value encountered in power 
nan 

與天然蟒蛇花車,numpy的雙打通常拒絕參加行動導致複雜的結果:

>>> np.sqrt(-1) 
__main__:1: RuntimeWarning: invalid value encountered in sqrt 
nan 

一個快速的解決辦法,我建議增加一個np.abs調用你的函數,並使用合適的界限進行擬合,以確保這不會導致僞裝。如果你的模型接近真相,你的樣本(我的意思是你樣本中的餘弦值)是正的,那麼在它周圍增加一個絕對值應該是一個無操作(更新:我意識到情況絕非如此,請看正確的方法下面)。

def f(x, Amp, n, b): 

    return Amp*(np.abs(np.cos(x)))**n + b # only change here 

有了這個小小的改變,我得到這樣的:

result is fine

作爲參考,從擬合是(4.96482314, 2.03690954, 5.03709923])比較生成與(5,2,5)參數。


發出後多一點想我意識到,餘弦將總是爲負半域(杜)。所以我建議的解決方法可能會有點問題,或者至少它的正確性不是微不足道的。另一方面,考慮到包含cos(x)^n的原始公式,cos(x)的值爲負值,如果n是整數,則這隻適用於模型,否則會得到複雜的結果。由於我們無法解決Diophantine擬合問題,因此我們需要正確處理。

最合適的方式(我的意思是偏差數據的可能性最小的方式)是這樣的:首先用模型將擬合數據轉換爲複數,然後將複雜數值輸出:

def f(x, Amp, n, b): 

    return Amp*np.abs(np.cos(x.astype(np.complex128))**n) + b 

這顯然是比我的解決方法的效率低得多,因爲每個配件的步驟,我們創建一個新的網格,無論是在複雜的運算和一個額外的量計算的形式做一些額外的工作。這給了我下面的配合,即使沒有設置界限:

improved answer, first part

的參數是(5.02849409, 1.97655728, 4.96529108)。這些也很接近。但是,如果我們把這些數值放回到實際模型中(沒有np.abs),我們得到的虛數部分大到-0.37,這並不是很大但是很重要。

所以第二步應該是重新擬合一個合適的模型---一個整數指數。從你的體型中選出一個明顯的指數2,然後對這個模型進行一個新的擬合。我不相信任何其他方法會給你一個數學上合理的結果。你也可以從最初的popt開始,希望它確實接近真相。當然,我們可以將原始函數與一些currying一起使用,但使用模型的專用雙特定版本要快得多。

from __future__ import print_function 
import numpy as np 
from scipy.optimize import curve_fit 
from matplotlib.pyplot import subplots, show 

def f_aux(x, Amp, n, b): 
    return Amp*np.abs(np.cos(x.astype(np.complex128))**n) + b 

def f_real(x, Amp, n, b): 
    return Amp*np.cos(x)**n + b 


x = np.arange(0, 2*np.pi, 0.01) # pi 
randomPart = np.random.rand(len(x)) - 0.5 
sample = f(x, 5, 2, 5) + randomPart 

fig,(frame_aux,frame) = subplots(ncols=2) 
for fr in frame_aux,frame: 
    fr.plot(x, sample, label="Sample measurements") 
    fr.legend() 
    fr.set_xlabel("x") 
    fr.set_ylabel("y") 

# auxiliary fit for n value 
popt_aux, pcov_aux = curve_fit(f_aux, x, sample, p0=(1,1,1)) 

modeldata = f(x, *popt_aux) 
#print(modeldata) 
print('Auxiliary fit parameters: {}'.format(popt_aux)) 
frame_aux.plot(x, modeldata, label="Auxiliary fit") 

# check visually, test if it's close to an integer, but otherwise 
n = np.round(popt_aux[1]) 

# actual fit with integral exponent 
popt, pcov = curve_fit(lambda x,Amp,b,n=n: f_real(x,Amp,n,b), x, sample, p0=(popt_aux[0],popt_aux[2])) 

modeldata = f(x, popt[0], n, popt[1]) 
#print(modeldata) 
print('Final fit parameters: {}'.format([popt[0],n,popt[1]])) 
frame.plot(x, modeldata, label="Best fit") 

frame_aux.legend() 
frame.legend() 

show() 

請注意,我改變了你的代碼中的一些東西,這並不影響我的觀點。從上面的圖中,這樣的一個,同時顯示了輔助配合和正確的一個:

final fig

輸出:

Auxiliary fit parameters: [ 5.02628994 2.00886409 5.00652371] 
Final fit parameters: [5.0288141074549699, 2.0, 5.0009730316739462] 

只是重申:雖然可能沒有視覺差在輔助配合和正確配合之間,只有後者給你的問題提供了有意義的答案。