2013-08-20 11 views
5

Ho il seguente codice:Passo tupla come argomento di input per 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)) 

alzerà TypeError: func() prende esattamente 2 argomenti (3 proposta). Bene, sembra azzeccato - curva_fit non interessa il (0, 0) per essere due input scalari. Così ho provato questo:

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

Ancora, detto: ValueError: oggetto troppo profonda per allineamento desiderato

Se Ho lasciato come difetto (non specificando p0):

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

Solleverà IndexError: indice non valido alla variabile scalare. Ovviamente, ha dato alla funzione solo uno scalare per p.

Posso rendere def func (x, p1, p2): restituisce p1 + p2 + x per farlo funzionare, ma con situazioni più complicate il codice sembrerà prolisso e disordinato. Mi piacerebbe davvero tanto se c'è una soluzione più pulita a questo problema.

Grazie!

risposta

3

Problema

Quando si utilizza curve_fit si deve dire in modo esplicito il numero di parametri in forma. Fare qualcosa di simile:

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

sarebbe grande, dal momento che sarebbe stato un ordine n-esimo funzione di raccordo polinomiale generale, ma purtroppo, a mio SciPy 0.12.0, si solleva:

ValueError: Unable to determine number of fit parameters. 

Soluzione

così si dovrebbe fare:

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

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

e così via ...

012.

Poi si può chiamare utilizzando l'argomento p0:

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

Non so se questo è più pulita, ma almeno è più facile ora per aggiungere più parametri alla funzione di raccordo. Forse si potrebbe persino fare una soluzione ancora migliore.

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: Questo funziona per me

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 

Spiegando l'idea

La funzione per il montaggio dovrebbe prendere solo scalari (non: *p0). Ricordare che il risultato della misura dipende dai parametri di inizializzazione.

esempio Lavorare

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

può questo approccio essere esteso oltre la semplice una tupla di 2 valori? Che dire di 3,4,5, ecc.? – wandadars

1

È possibile definire funzioni che restituiscono altre funzioni (vedi Passing additional arguments using scipy.optimize.curve_fit?)

esempio di lavoro:

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() 
Problemi correlati