ajustar múltiples gaussianos a los datos en python

Me pregunto si hay una manera fácil de implementar ajustes gaussianos / lorentzianos a 10 picos y extraer fwhm y también determinar la posición de fwhm en los valores de x. La forma complicada es separar los picos y ajustar los datos y extraer fwhm.

Los datos son [ https://drive.google.com/file/d/0B6sUnnbyNGuOT2RZb2UwYXU4dlE/view?usp=sharing] .

Cualquier consejo muy apreciado. Gracias.

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  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' 

Esto requiere un ajuste no lineal. Una buena herramienta para esto es la función curve_fit de curve_fit ‘s.

Para usar curve_fit , necesitamos una función de modelo, curve_fit func , que toma x y nuestros parámetros (adivinados) como argumentos y devuelve los valores correspondientes para y . Como nuestro modelo, utilizamos una sum de gaussianos:

 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 

Ahora, vamos a crear una conjetura inicial para nuestros parámetros. Esta conjetura comienza con picos en x=0 y x=1,000 con amplitud 60,000 y anchos de plegado en e de 80. Luego, agregamos picos candidatos en x=60, 140, 220, ... con amplitud 46,000 y ancho de 25:

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

Ahora, estamos listos para realizar el ajuste:

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

Para ver qué tan bien lo hicimos, dibujemos los valores y reales (curva negra sólida) y el fit (curva roja discontinua) contra x :

introduzca la descripción de la imagen aquí

Como puede ver, el ajuste es bastante bueno.

Código de trabajo completo

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