Pass tuple as input argument for scipy.optimize.curve_fit

与世无争的帅哥 提交于 2019-12-03 12:42:24

Not sure if this is cleaner, but at least it is easier now to add more parameters to the fitting function. Maybe one could even make an even better solution out of this.

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: This works for 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

Problem

When using curve_fit you must explicitly say the number of fit parameters. Doing something like:

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

would be great, since it would be a general nth-order polynomial fitting function, but unfortunately, in my SciPy 0.12.0, it raises:

ValueError: Unable to determine number of fit parameters.

Solution

So you should do:

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

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

and so forth...

Then you can call using the p0 argument:

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

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

Explaining the idea

The function to be fitted should take only scalars (not: *p0). Remember that the result of the fit depends on the initialization parameters.

Working example

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

You can define functions that return other functions (see Passing additional arguments using scipy.optimize.curve_fit? )

Working example :

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()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!