power - Python curve_fit con mĂșltiples variables independientes
scipy gaussian fit (5)
Puede pasar
curve_fit
una matriz multidimensional para las variables independientes, pero su
func
debe aceptar lo mismo.
Por ejemplo, llamando a esta matriz
X
y descomprimiéndola en
x
,
y
para mayor claridad:
import numpy as np
from scipy.optimize import curve_fit
def func(X, a, b, c):
x,y = X
return np.log(a) + b*np.log(x) + c*np.log(y)
# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 101)
a, b, c = 10., 4., 6.
z = func((x,y), a, b, c) * 1 + np.random.random(101) / 100
# initial guesses for a,b,c:
p0 = 8., 2., 7.
print curve_fit(func, (x,y), z, p0)
Da el ajuste:
(array([ 9.99933937, 3.99710083, 6.00875164]), array([[ 1.75295644e-03, 9.34724308e-05, -2.90150983e-04],
[ 9.34724308e-05, 5.09079478e-06, -1.53939905e-05],
[ -2.90150983e-04, -1.53939905e-05, 4.84935731e-05]]))
El
curve_fit
de Python calcula los parámetros de mejor ajuste para una función con una sola variable independiente, pero ¿hay alguna manera, usando
curve_fit
u otra cosa, para ajustar una función con múltiples variables independientes?
Por ejemplo:
def func(x, y, a, b, c):
return log(a) + b*log(x) + c*log(y)
donde x e y son la variable independiente y nos gustaría ajustar para a, b y c.
Sí, hay: simplemente dele a
curve_fit
una matriz multidimensional para
xData
.
Si. Podemos pasar múltiples variables para curve_fit . He escrito un código:
import numpy as np x = np.random.randn(2,100) w = np.array([1.5,0.5]).reshape(1,2) esp = np.random.randn(1,100) y = np.dot(w,x)+esp y = y.reshape(100,)
En el código anterior he generado x un conjunto de datos 2D en forma de (2,100), es decir, hay dos variables con 100 puntos de datos. He ajustado la variable dependiente y con variables independientes x con algo de ruido.
def model_func(x,w1,w2,b): w = np.array([w1,w2]).reshape(1,2) b = np.array([b]).reshape(1,1) y_p = np.dot(w,x)+b return y_p.reshape(100,)
Hemos definido una función modelo que establece una relación entre
y
&
x
.
Nota:
La forma de salida de la función del modelo o
y
pronosticada debe ser (longitud de
x
,)
popt, pcov = curve_fit(model_func,x,y)
El popt es una matriz numpy 1D que contiene parámetros predichos. En nuestro caso hay 3 parámetros.
Ajuste a un número desconocido de parámetros
En este ejemplo, intentamos reproducir algunos datos medidos
measData
.
En este ejemplo,
measData
es generado por la función
measuredData(x, a=.2, b=-2, c=-.8, d=.1)
.
Practico, podríamos haber medido
measData
de alguna manera, por lo que no tenemos idea de cómo se describe matemáticamente.
De ahí el ajuste.
polynomFit(inp, *args)
mediante un polinomio, que se describe mediante la función
polynomFit(inp, *args)
.
Como queremos probar diferentes órdenes de polinomios, es importante ser flexible en la cantidad de parámetros de entrada.
Las variables independientes (x e y en su caso) están codificadas en las ''columnas'' / segunda dimensión de
inp
.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def measuredData(inp, a=.2, b=-2, c=-.8, d=.1):
x=inp[:,0]
y=inp[:,1]
return a+b*x+c*x**2+d*x**3 +y
def polynomFit(inp, *args):
x=inp[:,0]
y=inp[:,1]
res=0
for order in range(len(args)):
print(14,order,args[order],x)
res+=args[order] * x**order
return res +y
inpData=np.linspace(0,10,20).reshape(-1,2)
inpDataStr=[''({:.1f},{:.1f})''.format(a,b) for a,b in inpData]
measData=measuredData(inpData)
fig, ax = plt.subplots()
ax.plot(np.arange(inpData.shape[0]), measData, label=''measuered'', marker=''o'', linestyle=''none'' )
for order in range(5):
print(27,inpData)
print(28,measData)
popt, pcov = curve_fit(polynomFit, xdata=inpData, ydata=measData, p0=[0]*(order+1) )
fitData=polynomFit(inpData,*popt)
ax.plot(np.arange(inpData.shape[0]), fitData, label=''polyn. fit, order ''+str(order), linestyle=''--'' )
ax.legend( loc=''upper left'', bbox_to_anchor=(1.05, 1))
print(order, popt)
ax.set_xticklabels(inpDataStr, rotation=90)
Resultado:
def func(X, a, b, c):
x,y = X
return np.log(a) + b*np.log(x) + c*np.log(y)
# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 101)
a, b, c = 10., 4., 6.
z = func((x,y), a, b, c) * 1 + np.random.random(101) / 100
# initial guesses for a,b,c:
p0 = 8., 2., 7.
print curve_fit(func, (x,y), z, p0)