library - ajustar mĂșltiples gaussianos a los datos en python
scipy library (1)
Esto requiere un ajuste no lineal. Una buena herramienta para esto es la función curve_fit de curve_fit
.
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, usamos una suma 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, creemos una conjetura inicial para nuestros parámetros. Esta suposición comienza con picos en x=0
x=1,000
con amplitud 60,000 y anchos de plegado e de 80. Luego, agregamos picos candidatos a 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, trazamos los valores y
reales (curva negra sólida) y el fit
(curva roja discontinua) contra x
:
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()
Me pregunto si existe una manera fácil de implementar ajustes gaussianos / lorentzianos en 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 <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''