2013-08-20 7 views
5

Mam następujący kod:Przełęcz krotka jako argument wejściowy dla 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)) 

to podniesie Błąd typu: func() wykonuje dokładnie 2 argumenty (3 podany). No cóż, to brzmi fair - curve_fit wypalić (0, 0) na dwa wejścia skalarne. Więc próbowałem to:

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

Ponownie, to powiedział: ValueError: Przedmiot zbyt głęboko do żądanej tablicy

Gdybym opuścił go jako domyślny (nie określającego P0):

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

Wzniesie on IndexError: nieprawidłowy indeks do zmiennej skalarnej. Oczywiście, dała tylko funkcję skalarną dla p.

mogę zrobić def func (x, P1, P2): Powrót P1 + P2 + x, aby dostać pracę, ale z bardziej skomplikowanych sytuacjach kod będzie wyglądać gadatliwym i niechlujny. Naprawdę bym to uwielbiał, gdyby było czystsze rozwiązanie tego problemu.

Dzięki!

Odpowiedz

3

Problem

Podczas korzystania curve_fit trzeba wyraźnie powiedzieć liczbę parametrów dopasowania. Robi coś takiego:

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

byłoby świetnie, ponieważ byłoby to ogólny wielomian n-tego rzędu funkcji montażu, ale niestety w moim scipy 0.12.0, podnosi:

ValueError: Unable to determine number of fit parameters. 

rozwiązanie

więc należy zrobić:

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

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

i tak dalej ...

Następnie można wywołać za pomocą p0 argumentu:

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

nie wiem, czy to jest czystsze, ale przynajmniej łatwiej jest teraz, aby dodać więcej parametrów do funkcji dopasowania. Może z tego można nawet zrobić lepsze rozwiązanie.

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: To działa na mnie

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 

Wyjaśniając pojęcia

funkcję, która ma być zamontowane powinny tylko skalary (nie: *p0). Pamiętaj, że wynik dopasowania zależy od parametrów inicjalizacji.

przykład Praca

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

Czy podejście to być przedłużony tylko krotka 2 wartości? A co z 3,4,5 itd.? – wandadars

1

można określić funkcje, które zwracają inne funkcje (patrz Passing additional arguments using scipy.optimize.curve_fit?)

przykład robocza:

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