简体   繁体   English

在scipy函数curve_fit中使用未确定数量的参数

[英]using undetermined number of parameters in scipy function curve_fit

First question: I'm trying to fit experimental datas with function of the following form: 第一个问题:我正在尝试使用以下形式的函数来拟合实验数据:

f(x) = m_o*(1-exp(-t_o*x)) + ... + m_j*(1-exp(-t_j*x))

Currently, I don't find a way to have an undetermined number of parameters m_j, t_j, I'm forced to do something like this: 目前,我没有找到一种方法来获得不确定数量的参数m_j,t_j,我被迫做这样的事情:

def fitting_function(x, m_1, t_1, m_2, t_2):
    return m_1*(1.-numpy.exp(-t_1*x)) + m_2*(1.-numpy.exp(-t_2*x)) 

parameters, covariance = curve_fit(fitting_function, xExp, yExp, maxfev = 100000)

(xExp and yExp are my experimental points) (xExp和yExp是我的实验点)

Is there a way to write my fitting function like this: 有没有办法写这样的拟合函数:

def fitting_function(x, li):
    res = 0.
    for el in range(len(li) / 2):
        res += li[2*idx]*(1-numpy.exp(-li[2*idx+1]*x))
    return res

where li is the list of fitting parameters and then do a curve_fitting? 其中li是拟合参数列表,然后执行curve_fitting? I don't know how to tell to curve_fitting what is the number of fitting parameters. 我不知道怎么告诉curve_fitting什么是拟合参数的数量。 When I try this kind of form for fitting_function, I have errors like "ValueError: Unable to determine number of fit parameters." 当我为fitting_function尝试这种形式时,我遇到了类似“ValueError:无法确定拟合参数的数量”的错误。

Second question: Is there any way to force my fitting parameters to be positive? 第二个问题:有没有办法强制我的拟合参数是积极的?

Any help appreciated :) 任何帮助赞赏:)

See my question and answer here . 在这里查看我的问题和答案。 I've also made a minimal working example demonstrating how it could be done for your application. 我还做了一个最小的工作示例,演示了如何为您的应用程序完成它。 I make no claims that this is the best way - I am muddling through all this myself, so any critiques or simplifications are appreciated. 我没有声称这是最好的方式 - 我自己也在混淆所有这些,所以任何批评或简化都会受到赞赏。

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

def wrapper(x, *args): #take a list of arguments and break it down into two lists for the fit function to understand
    N = len(args)/2
    amplitudes = list(args[0:N])
    timeconstants = list(args[N:2*N])
    return fit_func(x, amplitudes, timeconstants)


def fit_func(x, amplitudes, timeconstants): #the actual fit function
    fit = np.zeros(len(x))
    for m,t in zip(amplitudes, timeconstants):
        fit += m*(1.0-np.exp(-t*x))
    return fit

def gen_data(x, amplitudes, timeconstants, noise=0.1): #generate some fake data
    y = np.zeros(len(x))
    for m,t in zip(amplitudes, timeconstants):
        y += m*(1.0-np.exp(-t*x))
    if noise:
        y += np.random.normal(0, noise, size=len(x))
    return y


def main():
    x = np.arange(0,100)
    amplitudes = [1, 2, 3]
    timeconstants = [0.5, 0.2, 0.1]
    y = gen_data(x, amplitudes, timeconstants, noise=0.01)

    p0 = [1, 2, 3, 0.5, 0.2, 0.1]
    popt, pcov = curve_fit(lambda x, *p0: wrapper(x, *p0), x, y, p0=p0) #call with lambda function
    yfit = gen_data(x, popt[0:3], popt[3:6], noise=0)
    pl.plot(x,y,x,yfit)
    pl.show()
    print popt
    print pcov

if __name__=="__main__":
    main()

A word of warning, though. 但是有一个警告的话。 A linear sum of exponentials is going to make the fit EXTREMELY sensitive to any noise, particularly for a large number of parameters. 指数的线性和将使得拟合对任何噪声都非常敏感,特别是对于大量参数。 You can test that by adding even a small amount of noise to the data generated in the script - even small deviations cause it to get the wrong answer entirely while the fit still looks perfectly valid by eye (test with noise=0, 0.01, and 0.1). 您可以通过向脚本中生成的数据添加甚至少量的噪声来测试 - 即使是小的偏差也会导致它完全得到错误的答案,而拟合仍然看起来完全有效(通过噪声= 0,0.01和0.1)。 Be very careful interpreting your results even if the fit looks good. 即使合身看起来很好,也要非常小心地解释你的结果。 It's also a form that allows for variable swapping: the best fit solution is the same even if you swap any pairs of (m_i, t_i) with (m_j, t_j), meaning your chi-square has multiple identical local minima that might mean your variables get swapped around during fitting, depending on your initial conditions. 它也是一个允许变量交换的形式:即使你将任何一对(m_i,t_i)与(m_j,t_j)交换,最合适的解决方案也是一样的,这意味着你的卡方有多个相同的局部最小值可能意味着你的在拟合期间,变量会被交换,具体取决于您的初始条件。 This is unlikely to be a numeriaclly robust way to extract these parameters. 这不太可能是提取这些参数的一种非常可靠的方法。

To your second question, yes, you can, by defining your exponentials like so: 对于你的第二个问题,是的,你可以通过定义你的指数来这样:

m_0**2*(1.0-np.exp(-t_0**2*x)+...

Basically, square them all in your actual fit function, fit them, and then square the results (which could be negative or positive) to get your actual parameters. 基本上,将它们全部放在您的实际拟合函数中,使它们适合它们,然后将结果平方(可能是负数或正数)以获得实际参数。 You can also define variables to be between a certain range by using different proxy forms. 您还可以使用不同的代理表单将变量定义在特定范围之间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM