簡體   English   中英

將多個高斯擬合到python中的數據

[英]fit multiple gaussians to the data in python

我只是想知道是否有一種簡單的方法來實現 10 個峰值的高斯/洛倫茲擬合並提取 fwhm 並確定 fwhm 在 x 值上的位置。 復雜的方法是分離峰值並擬合數據並提取fwhm。

數據是 [ https://drive.google.com/file/d/0B6sUnnbyNGuOT2RZb2UwYXU4dlE/view?usp=sharing]

任何建議不勝感激。 謝謝。

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

data = np.loadtxt('data.txt', delimiter=',')
x, y = data

plt.plot(x,y)
plt.show()

def func(x, *params):
    y = np.zeros_like(x)
    print len(params)
    for i in range(0, len(params), 3):
        ctr = params[i]
        amp = params[i+1]
        wid = params[i+2]
        y = y + amp * np.exp( -((x - ctr)/wid)**2)



guess = [0, 60000, 80, 1000, 60000, 80]
for i in range(12):
    guess += [60+80*i, 46000, 25]


popt, pcov = curve_fit(func, x, y, p0=guess)
print popt
fit = func(x, *popt)

plt.plot(x, y)
plt.plot(x, fit , 'r-')
plt.show()



Traceback (most recent call last):
File "C:\Users\test.py", line 33, in <module>
popt, pcov = curve_fit(func, x, y, p0=guess)
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 533, in curve_fit
res = leastsq(func, p0, args=args, full_output=1, **kw)
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 368, in leastsq
shape, dtype = _check_func('leastsq', 'func', func, x0, args, n)
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 19, in _check_func
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 444, in    _ general_function
return function(xdata, *params) - ydata
TypeError: unsupported operand type(s) for -: 'NoneType' and 'float'

這需要非線性擬合。 一個很好的工具是 scipy 的curve_fit函數。

要使用curve_fit ,我們需要一個模型函數,將其稱為func ,它將x和我們的(猜測的)參數作為參數並返回y的相應值。 作為我們的模型,我們使用高斯總和:

from scipy.optimize import curve_fit
import numpy as np

def func(x, *params):
    y = np.zeros_like(x)
    for i in range(0, len(params), 3):
        ctr = params[i]
        amp = params[i+1]
        wid = params[i+2]
        y = y + amp * np.exp( -((x - ctr)/wid)**2)
    return y

現在,讓我們為我們的參數創建一個初始猜測。 這個猜測從x=0x=1,000處的峰值開始,振幅為 60,000,e 折疊寬度為 80。然后,我們在x=60, 140, 220, ... 60、140、220 處添加候選峰值,振幅為 46,000,寬度為 25:

guess = [0, 60000, 80, 1000, 60000, 80]
for i in range(12):
    guess += [60+80*i, 46000, 25]

現在,我們准備執行擬合:

popt, pcov = curve_fit(func, x, y, p0=guess)
fit = func(x, *popt)

為了看看我們做得有多好,讓我們繪制實際的y值(黑色實線曲線)和對xfit (紅色虛線曲線):

在此處輸入圖片說明

如您所見,合身度相當不錯。

完整的工作代碼

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

data = np.loadtxt('data.txt', delimiter=',')
x, y = data

plt.plot(x,y)
plt.show()

def func(x, *params):
    y = np.zeros_like(x)
    for i in range(0, len(params), 3):
        ctr = params[i]
        amp = params[i+1]
        wid = params[i+2]
        y = y + amp * np.exp( -((x - ctr)/wid)**2)
    return y

guess = [0, 60000, 80, 1000, 60000, 80]
for i in range(12):
    guess += [60+80*i, 46000, 25]   

popt, pcov = curve_fit(func, x, y, p0=guess)
print popt
fit = func(x, *popt)

plt.plot(x, y)
plt.plot(x, fit , 'r-')
plt.show()

@ john1024 的回答很好,但需要一個手動過程來生成初始猜測。 這是自動開始猜測的簡單方法。 將相關的 3 行 john1024 代碼替換為以下內容:

    import scipy.signal
    i_pk = scipy.signal.find_peaks_cwt(y, widths=range(3,len(x)//Npks))
    DX = (np.max(x)-np.min(x))/float(Npks) # starting guess for component width
    guess = np.ravel([[x[i], y[i], DX] for i in i_pk]) # starting guess for (x, amp, width) for each component

恕我直言,始終建議在此類問題中繪制殘差(數據 - 模型)。 您還需要查看擬合的 ChiSq。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM