2013-08-20 4 views
5

J'ai le code suivant:passe comme argument tuple d'entrée pour scipy.optimize.curve_fit

import numpy as np 
from scipy.optimize import curve_fit 


def func(x, p): return p[0] + p[1] + x 


popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=(0, 0)) 

Il soulèvera TypeError: func() prend exactement 2 arguments (3 donné). Eh bien, cela semble juste - curve_fit décompacte le (0, 0) pour qu'il y ait deux entrées scalaires. J'ai donc essayé ceci:

popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=((0, 0),)) 

Encore une fois, il a dit: ValueError: objet trop profond pour le tableau désiré

Si je l'ai laissé par défaut (ne pas spécifier p0):

popt, pcov = curve_fit(func, np.arange(10), np.arange(10)) 

Il va augmenter IndexError: index invalide à la variable scalaire. Évidemment, cela n'a donné à la fonction qu'un scalaire pour p.

Je peux faire def func (x, p1, p2): retourner p1 + p2 + x pour le faire fonctionner, mais avec des situations plus compliquées, le code va paraître bavard et désordonné. J'adorerais vraiment qu'il y ait une solution plus propre à ce problème.

Merci!

Répondre

3

Problème

Lorsque vous utilisez curve_fit vous devez dire explicitement le nombre de paramètres d'ajustement. Faire quelque chose comme:

def f(x, *p): 
    return sum([p[i]*x**i for i in range(len(p))]) 

serait génial, car ce serait une fonction d'ajustement polynomiale général d'ordre n, mais malheureusement, dans mon SciPy 0.12.0, il soulève:

ValueError: Unable to determine number of fit parameters. 

Solution

alors vous devriez faire:

def f_1(x, p0, p1): 
    return p0 + p1*x 

def f_2(x, p0, p1, p2): 
    return p0 + p1*x + p2*x**2 

et ainsi de suite ...

Ensuite, vous pouvez appeler en utilisant l'argument p0:

curve_fit(f_1, xdata, ydata, p0=(0,0)) 
4

Je ne sais pas si cela est plus propre, mais au moins il est plus facile maintenant d'ajouter des paramètres à la fonction d'ajustement. Peut-être que l'on pourrait même faire une meilleure solution à partir de cela.

import numpy as np 
from scipy.optimize import curve_fit 


def func(x, p): return p[0] + p[1] * x 

def func2(*args): 
    return func(args[0],args[1:]) 

popt, pcov = curve_fit(func2, np.arange(10), np.arange(10), p0=(0, 0)) 
print popt,pcov 

EDIT: Cela fonctionne pour moi

import numpy as np 
from scipy.optimize import curve_fit 

def func(x, *p): return p[0] + p[1] * x 

popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=(0, 0)) 
print popt,pcov 
1

scipy.optimize.curve_fit

scipy.optimize.curve_fit(f, xdata, ydata, p0=None, sigma=None, **kw)

Use non-linear least squares to fit a function, f, to data. 

Assumes ydata = f(xdata, *params) + eps 

Expliquer l'idée

La fonction à monter doit prendre seulement scalaires (pas: *p0). Rappelez-vous que le résultat de l'ajustement dépend des paramètres d'initialisation.

Exemple de travail

import numpy as np 
from scipy.optimize import curve_fit 
import matplotlib.pyplot as plt 

def func(x, a0, a1): 
    return a0 + a1 * x 

x, y = np.arange(10), np.arange(10) + np.random.randn(10)/10 
popt, pcov = curve_fit(func, x, y, p0=(1, 1)) 

# Plot the results 
plt.title('Fit parameters:\n a0=%.2e a1=%.2e' % (popt[0], popt[1])) 
# Data 
plt.plot(x, y, 'rx') 
# Fitted function 
x_fine = np.linspace(x[0], x[-1], 100) 
plt.plot(x_fine, func(x_fine, popt[0], popt[1]), 'b-') 
plt.savefig('Linear_fit.png') 
plt.show() 

Result from the fit is shown in the plot.

+0

cette approche peut être étendue au-delà un tuple de 2 valeurs? Qu'en est-il de 3,4,5, etc? – wandadars

1

Vous pouvez définir des fonctions qui renvoient d'autres fonctions (voir Passing additional arguments using scipy.optimize.curve_fit?)

Exemple de travail:

import numpy as np 
import random 
from scipy.optimize import curve_fit 
from matplotlib import pyplot as plt 
import math 

def funToFit(x): 
    return 0.5+2*x-3*x*x+0.2*x*x*x+0.1*x*x*x*x 


xx=[random.uniform(1,5) for i in range(30)] 
yy=[funToFit(xx[i])+random.uniform(-1,1) for i in range(len(xx))] 


a=np.zeros(5) 
def make_func(numarg): 
    def func(x,*a): 
     ng=numarg 
     v=0 
     for i in range(ng): 
      v+=a[i]*np.power(x,i) 
     return v 
    return func 

leastsq, covar = curve_fit(make_func(len(a)),xx,yy,tuple(a)) 
print leastsq 
def fFited(x): 
    v=0 
    for i in range(len(leastsq)): 
     v+=leastsq[i]*np.power(x,i) 
    return v 


xfine=np.linspace(1,5,200) 
plt.plot(xx,yy,".") 
plt.plot(xfine,fFited(xfine)) 
plt.show() 
Questions connexes