python - power - scipy gaussian fit
scipy.optimize.curve_fit no puede ajustarse a la curva gaussiana sesgada desplazada (2)
Intento ajustar una curva gaussiana sesgada y desplazada usando la función curve_fit de scipy , pero me parece que bajo ciertas condiciones la adaptación es bastante pobre, a menudo me da una línea recta o casi exacta.
El código a continuación se deriva de la documentación curve_fit
. El código proporcionado es un conjunto arbitrario de datos para fines de prueba, pero muestra el problema bastante bien.
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import math as math
import scipy.special as sp
#def func(x, a, b, c):
# return a*np.exp(-b*x) + c
def func(x, sigmag, mu, alpha, c,a):
#normal distribution
normpdf = (1/(sigmag*np.sqrt(2*math.pi)))*np.exp(-(np.power((x-mu),2)/(2*np.power(sigmag,2))))
normcdf = (0.5*(1+sp.erf((alpha*((x-mu)/sigmag))/(np.sqrt(2)))))
return 2*a*normpdf*normcdf + c
x = np.linspace(0,100,100)
y = func(x, 10,30, 0,0,1)
yn = y + 0.001*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn,) #p0=(9,35,0,9,1))
y_fit= func(x,popt[0],popt[1],popt[2],popt[3],popt[4])
plt.plot(x,yn)
plt.plot(x,y_fit)
El problema parece aparecer cuando cambio el gaussiano demasiado lejos de cero (usando mu
). Intenté dar valores iniciales, incluso aquellos idénticos a mi función original, pero no resuelve el problema. Para un valor de mu=10
, curve_fit
funciona perfectamente, pero si uso mu>=30
ya no se ajusta a los datos.
Dar puntos de partida para la minimización a menudo funciona de maravilla. Intente darle al minimizer información sobre la posición del máximo y el ancho de la curva:
popt, pcov = curve_fit(func, x, yn, p0=(1./np.std(yn), np.argmax(yn) ,0,0,1))
Cambiar esta única línea en su código con sigma=10
y mu=50
produce
Puede llamar a curve_fit
muchas veces con una conjetura inicial aleatoria y elegir los parámetros con un error mínimo.
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import math as math
import scipy.special as sp
def func(x, sigmag, mu, alpha, c,a):
#normal distribution
normpdf = (1/(sigmag*np.sqrt(2*math.pi)))*np.exp(-(np.power((x-mu),2)/(2*np.power(sigmag,2))))
normcdf = (0.5*(1+sp.erf((alpha*((x-mu)/sigmag))/(np.sqrt(2)))))
return 2*a*normpdf*normcdf + c
x = np.linspace(0,100,100)
y = func(x, 10,30, 0,0,1)
yn = y + 0.001*np.random.normal(size=len(x))
results = []
for i in xrange(50):
p = np.random.randn(5)*10
try:
popt, pcov = curve_fit(func, x, yn, p)
except:
pass
err = np.sum(np.abs(func(x, *popt) - yn))
results.append((err, popt))
if err < 0.1:
break
err, popt = min(results, key=lambda x:x[0])
y_fit= func(x, *popt)
plt.plot(x,yn)
plt.plot(x,y_fit)
print len(results)