[英]Python gaussian fit on simulated gaussian noisy data
我需要使用高斯擬合對來自儀器的數據進行插值。 為此我想過使用curve_fit
功能從scipy
。 由於我想先在假數據上測試此功能,然后再在儀器上嘗試使用此代碼,因此編寫了以下代碼來生成嘈雜的高斯數據並使之適合:
from scipy.optimize import curve_fit
import numpy
import pylab
# Create a gaussian function
def gaussian(x, a, b, c):
val = a * numpy.exp(-(x - b)**2 / (2*c**2))
return val
# Generate fake data.
zMinEntry = 80.0*1E-06
zMaxEntry = 180.0*1E-06
zStepEntry = 0.2*1E-06
x = numpy.arange(zMinEntry,
zMaxEntry,
zStepEntry,
dtype = numpy.float64)
n = len(x)
meanY = zMinEntry + (zMaxEntry - zMinEntry)/2
sigmaY = 10.0E-06
a = 1.0/(sigmaY*numpy.sqrt(2*numpy.pi))
y = gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
# Fit
popt, pcov = curve_fit(gaussian, x, y)
# Print results
print("Scale = %.3f +/- %.3f" % (popt[0], numpy.sqrt(pcov[0, 0])))
print("Offset = %.3f +/- %.3f" % (popt[1], numpy.sqrt(pcov[1, 1])))
print("Sigma = %.3f +/- %.3f" % (popt[2], numpy.sqrt(pcov[2, 2])))
pylab.plot(x, y, 'ro')
pylab.plot(x, gaussian(x, popt[0], popt[1], popt[2]))
pylab.grid(True)
pylab.show()
不幸的是,這不能正常工作,代碼輸出如下:
Scale = 6174.816 +/- 7114424813.672
Offset = 429.319 +/- 3919751917.830
Sigma = 1602.869 +/- 17923909301.176
繪制的結果是(藍色是擬合函數,紅色點是嘈雜的輸入數據):
我也嘗試着看這個答案,但不知道我的問題在哪里。 我在這里想念什么嗎? 還是我以錯誤的方式使用curve_fit
函數? 提前致謝!
就規模問題而言,我同意奧拉夫的觀點。 最佳參數相差許多數量級。 但是,縮放用於生成玩具數據的參數似乎無法解決實際應用中的問題。 curve_fit
使用lestsq
,它在數值上近似於Jacobian值,在該值上,由於比例不同而出現數字問題(嘗試在curve_fit
使用full_output
關鍵字)。
以我的經驗,通常最好使用不依賴於近似導數而僅使用函數值的fmin
。 現在,您必須編寫自己的最小二乘法以進行優化。
起始值仍然很重要。 你的情況,你可以通過采取最大振幅做出足夠好的猜測a
和相應的x值b
和c
。
在代碼中,它看起來像這樣:
from scipy.optimize import curve_fit,fmin
import numpy
import pylab
# Create a gaussian function
def gaussian(x, a, b, c):
val = a * numpy.exp(-(x - b)**2 / (2*c**2))
return val
# Generate fake data.
zMinEntry = 80.0*1E-06
zMaxEntry = 180.0*1E-06
zStepEntry = 0.2*1E-06
x = numpy.arange(zMinEntry,
zMaxEntry,
zStepEntry,
dtype = numpy.float64)
n = len(x)
meanY = zMinEntry + (zMaxEntry - zMinEntry)/2
sigmaY = 10.0E-06
a = 1.0/(sigmaY*numpy.sqrt(2*numpy.pi))
y = gaussian(x, a, meanY, sigmaY) + a*0.1*numpy.random.normal(0, 1, size=len(x))
print a, meanY, sigmaY
# estimate starting values from the data
a = y.max()
b = x[numpy.argmax(a)]
c = b
# define a least squares function to optimize
def minfunc(params):
return sum((y-gaussian(x,params[0],params[1],params[2]))**2)
# fit
popt = fmin(minfunc,[a,b,c])
# Print results
print("Scale = %.3f" % (popt[0]))
print("Offset = %.3f" % (popt[1]))
print("Sigma = %.3f" % (popt[2]))
pylab.plot(x, y, 'ro')
pylab.plot(x, gaussian(x, popt[0], popt[1], popt[2]),lw = 2)
pylab.xlim(x.min(),x.max())
pylab.grid(True)
pylab.show()
看起來一些數值不穩定性正在滲入優化器。 嘗試縮放數據。 帶有以下數據:
zMinEntry = 80.0*1E-06 * 1000
zMaxEntry = 180.0*1E-06 * 1000
zStepEntry = 0.2*1E-06 * 1000
sigmaY = 10.0E-06 * 1000
我得到的估計
Scale = 39.697 +/- 0.526
Offset = 0.130 +/- 0.000
Sigma = -0.010 +/- 0.000
將其與真實值進行比較:
Scale = 39.894228
Offset = 0.13
Sigma = 0.01
sigma的負號當然可以忽略。
這給出了以下情節
正如我在評論中所說,如果您提供合理的初始猜測,則擬合成功,即像這樣調用curve_fit
:
popt, pcov = curve_fit(gaussian, x, y, [50000,0.00012,0.00002])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.