How to use scipy.optimize.curve_fit to use lists of variable

强颜欢笑 提交于 2020-03-04 18:37:01

问题


I have time varying data trace which I want to fit a function to. The inputs to the functions are lists and I want the curve_fit to optimize all values in the list to fit the curve. I have gotten so far-

from scipy.optimize import curve_fit
from matplotlib.pylab import plt
from numpy import exp

def ffunc2(x, a, b):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(b[counter] * x)
        counter += 1
    return return_value

# INITIAL DATA
x = [1, 2, 3, 5]
y = [1, 8, 81, 125]


number_variable = 2

# INTIAL GUESS
p0 = []
counter = 0
while counter < number_variable:
    p0.append(0.0)
    counter += 1

p, _ = curve_fit(ffunc2, x, y, p0=[0.0, 0.0])

I want to create a loop which iterates such that it gives me the best fit with maximum number of variables by minimizing the error.

I have found this discussion as well - Using scipy curve_fit for a variable number of parameters

from numpy import exp
from scipy.optimize import curve_fit

def wrapper_fit_func(x, N, *args):
    a, b, c = list(args[0][:N]), list(args[0][N:2*N]), list(args[0][2*N:3*N])
    return fit_func(x, a, b)

def fit_func(x, a, b):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(b[counter] * x)
        counter += 1
    return return_value


x = [1, 2, 3, 5]
y = [1, 8, 81, 125]
params_0 = [0,1.0,2.0,3.0,4.0,5.0]

popt, pcov = curve_fit(lambda x, *params_0: wrapper_fit_func(x, 3, params_0), x, y, p0=params_0)

But get an error -´´´ File "C:\python\lib\site-packages\scipy\optimize\minpack.py", line 387, in leastsq raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m)) TypeError: Improper input: N=6 must not exceed M=4 ´´´


回答1:


I was able to solve this be using sci_py.optimize.least_squares directly as it takes in tuple as an input and not variables directly. But I do have to define the error function. I would assume it help solve my problem as of now.

from scipy.optimize import least_squares
from matplotlib.pylab import plt
from numpy import exp
import numpy as np


# define function to fit
def ffunc2(a, x):
    counter = 0
    return_value = 0
    while counter < len(a):
        return_value += a[counter] * exp(x * a[counter + 1])
        counter += 2

    return return_value


def error_func(tpl, x, y):
    return ffunc2(tpl,x) - y


# INPUT DATA
x = np.array([1, 2, 3, 5])
y = np.array([0.22103418, 0.24428055, 0.26997176, 0.32974425,])

# INITIAL GUESS
p0 = (1, 1)*10
output = least_squares(error_func, x0=p0, jac='2-point', bounds=(0, np.inf), method='trf', ftol=1e-08,
                       xtol=1e-08, gtol=1e-08, x_scale=1.0, loss='linear', f_scale=1.0, diff_step=None,
                       tr_solver=None,
                       tr_options={}, jac_sparsity=None, max_nfev=None, verbose=0, args=(x, y))

tpl_final = output.x
print (tpl_final)

final_curve = ffunc2(tpl_final,x)

plt.plot(x, y, 'r-', x, final_curve, 'g-')
plt.show()




回答2:


The short answer is "No". curve_fit requires a single list/ndarray of variable parameters that correspond, in order, with the arguments of the model function you provide. That is, you would have to explicitly name all the parameters in your function and make your list of lists of variables strictly 1D.

Then again, curve_fit is not much more than a wrapper around scipy.optimize.least_squares. To use that approach, you pass in a (still strictly 1D) list/ndarray and use those values to build the array to be minimized (typically data-model) from that single array of variables. In some complex cases with many components or data sets, that can become easier to use. That is, the curve_fit approach doesn't scale very well to 50 positional variables.

Depending on the nature of your problem, you might also find lmfit (https://lmfit.github.io/lmfit-py/ -- disclaimer: I am the original author) useful. This organizes Parameters by name, not position in a list and provides more built-in ways to constrain Parameters and explore uncertainties. What may be of particular for your case, the lmfit.Model class for curve-fitting includes the ability to easily add models together into a composite (for example, 2 Gaussians + n exponential background as shown at https://lmfit.github.io/lmfit-py/examples/documentation/builtinmodels_nistgauss2.html). That might help you express what you are trying to do.



来源:https://stackoverflow.com/questions/60335524/how-to-use-scipy-optimize-curve-fit-to-use-lists-of-variable

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