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

时间:2016-07-12 11:38:29

标签: python scipy curve-fitting

第一个问题: 我试图使用以下形式的函数来拟合实验数据:

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

目前,我还没有找到一种方法来确定参数数量不确定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和yExp是我的实验点)

有没有办法像这样编写我的拟合函数:

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

其中li是拟合参数列表,然后执行curve_fitting?我不知道怎么告诉curve_fitting什么是拟合参数的数量。 当我为fitting_function尝试这种形式时,我遇到了错误,例如" ValueError:无法确定拟合参数的数量。"

第二个问题: 有没有办法强制我的拟合参数是积极的?

任何帮助表示赞赏:)

1 个答案:

答案 0 :(得分:2)

查看我的问题和回答here。我还做了一个最小的工作示例,演示了如何为您的应用程序完成它。我并没有声称这是最好的方式 - 我自己也在混淆所有这些,所以任何批评或简化都会受到赞赏。

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()
但是,有一句警告。指数的线性和将使得拟合对任何噪声都非常敏感,特别是对于大量参数。您可以通过向脚本中生成的数据添加甚至少量的噪声来测试 - 即使是小的偏差也会导致它完全得到错误的答案,而拟合仍然看起来完全有效(通过噪声= 0,0.01和0.1)。即使合身看起来很好,也要非常小心地解释你的结果。它也是一种允许变量交换的形式:即使你将(m_i,t_i)的任何对与(m_j,t_j)交换,最佳拟合解也是相同的,这意味着你的卡方具有多个相同的局部最小值这可能意味着您的变量在拟合期间会被交换,具体取决于您的初始条件。这不太可能是提取这些参数的一种非常可靠的方法。

对于你的第二个问题,是的,你可以通过定义你的指数来实现:

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

基本上,将它们全部放在实际拟合函数中,拟合它们,然后将结果平方(可能是负数或正数)以获得实际参数。您还可以使用不同的代理表单将变量定义在特定范围之间。