ajuste negativo de la curva de scipy

Me gustaría encajar una curva con curve_fit y evitar que se vuelva negativa. Desafortunadamente, el código de abajo no funciona. ¿Alguna pista? ¡Muchas gracias!

 # Imports from scipy.optimize import curve_fit import numpy as np import matplotlib.pyplot as plt xData = [0.0009824379203203417, 0.0011014182912933933, 0.0012433979929054324, 0.0014147106052612918, 0.0016240300315499524, 0.0018834904507916608, 0.002210485320720769, 0.002630660216394964, 0.0031830988618379067, 0.003929751681281367, 0.0049735919716217296, 0.0064961201261998095, 0.008841941282883075, 0.012732395447351627, 0.019894367886486918, 0.0353677651315323, 0.07957747154594767, 0.3183098861837907] yData = [99.61973156923796, 91.79478510744039, 92.79302188621314, 84.32927272723863, 77.75060981602016, 75.62801782349504, 70.48026800610839, 72.21240551953743, 68.14019252499526, 55.23015406920851, 57.212682880377464, 50.777016257727176, 44.871140881319626, 40.544138806850846, 32.489105158795525, 25.65367127756607, 19.894206907130403, 13.057996247388862] def func(x,m,c,d): ''' Fitting Function I put d as an absolute number to prevent negative values for d? ''' return x**m * c + abs(d) p0 = [-1, 1, 1] coeff, _ = curve_fit(func, xData, yData, p0) # Fit curve m, c, d = coeff[0], coeff[1], coeff[2] print("d: " + str(d)) # Why is it negative!! 

Tu modelo realmente funciona bien como muestra la siguiente ttwig. Usé su código y graficé los datos originales y los datos que obtiene con los parámetros ajustados:

introduzca la descripción de la imagen aquí

Como puede ver, los datos pueden reproducirse muy bien, pero de hecho obtiene un valor negativo para d (que no debe ser algo malo dependiendo del contexto del modelo). Si desea evitarlo, le recomiendo usar lmfit donde puede restringir sus parámetros a ciertos rangos. La siguiente ttwig muestra el resultado. introduzca la descripción de la imagen aquí

Como puede ver, también reproduce bien los datos y obtiene un valor positivo para d como se desee.

a saber:

 m: -0.35199747 c: 8.48813181 d: 0.05775745 

Aquí está el código completo que reproduce las figuras:

 # Imports from scipy.optimize import curve_fit import numpy as np import matplotlib.pyplot as plt #additional import from lmfit import minimize, Parameters, Parameter, report_fit xData = [0.0009824379203203417, 0.0011014182912933933, 0.0012433979929054324, 0.0014147106052612918, 0.0016240300315499524, 0.0018834904507916608, 0.002210485320720769, 0.002630660216394964, 0.0031830988618379067, 0.003929751681281367, 0.0049735919716217296, 0.0064961201261998095, 0.008841941282883075, 0.012732395447351627, 0.019894367886486918, 0.0353677651315323, 0.07957747154594767, 0.3183098861837907] yData = [99.61973156923796, 91.79478510744039, 92.79302188621314, 84.32927272723863, 77.75060981602016, 75.62801782349504, 70.48026800610839, 72.21240551953743, 68.14019252499526, 55.23015406920851, 57.212682880377464, 50.777016257727176, 44.871140881319626, 40.544138806850846, 32.489105158795525, 25.65367127756607, 19.894206907130403, 13.057996247388862] def func(x,m,c,d): ''' Fitting Function I put d as an absolute number to prevent negative values for d? ''' print m,c,d return np.power(x,m)*c + d p0 = [-1, 1, 1] coeff, _ = curve_fit(func, xData, yData, p0) # Fit curve m, c, d = coeff[0], coeff[1], coeff[2] print("d: " + str(d)) # Why is it negative!! plt.scatter(xData, yData, s=30, marker = "v",label='P') plt.scatter(xData, func(xData, *coeff), s=30, marker = "v",color="red",label='curvefit') plt.show() #####the new approach starts here def func2(params, x, data): m = params['m'].value c = params['c'].value d = params['d'].value model = np.power(x,m)*c + d return model - data #that's what you want to minimize # create a set of Parameters params = Parameters() params.add('m', value= -2) #value is the initial condition params.add('c', value= 8.) params.add('d', value= 10.0, min=0) #min=0 prevents that d becomes negative # do fit, here with leastsq model result = minimize(func2, params, args=(xData, yData)) # calculate final result final = yData + result.residual # write error report report_fit(params) try: import pylab pylab.plot(xData, yData, 'k+') pylab.plot(xData, final, 'r') pylab.show() except: pass 

Podría usar la scipy.optimize.curve_fit de bounds del método scipy.optimize.curve_fit para especificar el límite máximo y el límite mínimo.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html

Bounds es una matriz de dos tuplas. En su caso, solo necesita especificar el límite inferior para d. Podría usar, bounds=([-np.inf, -np.inf, 0], np.inf)

Nota: Si proporciona un escalar como parámetro (por ejemplo: – como la segunda variable anterior), se aplica automáticamente como el límite superior para los tres coeficientes.

Solo necesitas agregar un pequeño argumento para restringir tus parámetros. Es decir:

curve_fit(func, xData, yData, p0, bounds=([m1,c1,d1],[m2,c2,d2]))

donde m1, c1, d1 son los límites inferiores de los parámetros (en su caso, deben ser 0) y m2, c2, d2 son los límites superiores.

Si desea que todos los valores de m, c, d sean positivos, el código debería ser el siguiente:

curve_fit(func, xData, yData, p0, bounds=(0,numpy.inf))

donde todos los parámetros tienen un límite inferior de 0 y un límite superior de infinito (sin límite)