【问题标题】:Python code for curve fitting by convolution of a gausian and multi exponential decay通过高斯和多指数衰减卷积进行曲线拟合的 Python 代码
【发布时间】:2020-01-01 13:22:48
【问题描述】:

我正在开发一个代码,用于用一个模型拟合数据,该模型是两个函数的卷积(具有多指数衰减的高斯 exp(Ax)+exp(Bx)+...)。基本上只有高斯和/或高斯修改https://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution 的拟合在 Lmfit 中工作得非常好,但使用内置卷积(即,如果使用两个函数的 np.convolve,Lmfit 不起作用。

我在互联网上尝试了很多示例,到目前为止,我意识到我的函数返回 inf 或 nan 值,而且数据在卷积中的使用间隔不相等。我通过使用卷积的数学表达式和使用 scipy.optimize.curve_fit 找到了一个绕道而行的问题。但这是一个非常笨拙且耗时的方法,我想找到一种方法来使其更复杂和通用两个函数的卷积并使用 lmfit 可以更轻松地控制参数。

该数据集也包含在 cmets 中作为您的参考。

w=0.1 # is constant
def CONVSum(x,w,*p):
    n=np.int(len(p)/3)
    A=p[:n]
    B=p[n:2*n]
    C=p[2*n:3*n]
# =======================================================================
#     below formula is derived as mathematical expression of convoluted multi exponential components with a gaussian distribution based on the instruction given in http://www.np.ph.bham.ac.uk/research_resources/programs/halflife/gauss_exp_conv.pdf
# ======================================================================
    fnct=sum(np.float64([A[i]*np.exp(-B[i]*((x-C[i])-(0.5*np.square(w)*B[i])))*(1+scipy.special.erf(((x-C[i])-(np.square(w)*B[i]))/(np.sqrt(2)*w))) for i in range(n)]))
    fnct[np.isnan(fnct)]=0
    fnct[fnct<1e-12]=0
    return fnct
N=4 #number of exponential functions to be fitted
params = np.linspace(1, 0.0001, N*3); #parameters for a multiple exponential                                                                                                                        
popt,pcov = curve_fit(CONVSum,x,y,p0=params,
    bounds=((0,0,0,0,-np.inf,-np.inf,-np.inf,-np.inf,-3,-3,-3,-3),
           (1,1,1,1, np.inf, np.inf, np.inf, np.inf, 3, 3, 3, 3)),
           maxfev = 1000000)

fitted data with curve fitt

任何关于高斯卷积和多重指数衰减拟合的帮助或提示都非常感谢,我更喜欢使用 lmfit,因为我可以很好地识别参数并将它们相互关联。

理想情况下,我想用参数拟合我的数据,其中一些在数据集之间共享,一些是延迟的 (+off_set)。

【问题讨论】:

标签: python curve-fitting convolution gaussian exponential


【解决方案1】:

嗯,您的脚本有点难以阅读,并且有很多与您的问题无关的内容。您的 exgauss 函数没有防止无穷大。 np.exp(x) for x>~ 710 会给出 Inf,拟合将无法进行。

【讨论】:

  • 尊敬的@M Newville 感谢您抽出宝贵时间回复,问题已通过使用 np.isnan() 消除 nan 和 inf 得到解决,但合适的操作系统仍然无法正常工作。我确实找到了编辑我的问题的方法,但我改变了一点。
【解决方案2】:

这里是问题中给出的固化拟合代码的等效项。我设法通过在here 和here 中使用非常棒的指令和信息来创建它。但它仍然需要开发。

    # =============================================================================
    #     below formula is drived as mathematical expresion of convoluted multi exponential components with a gausian distribution based on the instruction given in http://www.np.ph.bham.ac.uk/research_resources/programs/halflife/gauss_exp_conv.pdf
    # =============================================================================

def CONVSum(x,params):
    fnct=sum(
            np.float64([
                    (params['amp%s_%s'%(n,i)].value)*np.exp(-(params['dec%s_%s'%(n,i)].value)*((x-(params['cen%s_%s'%(n,i)].value))-
                     (0.5*np.square((params['sig%s_%s'%(n,i)].value))*(params['dec%s_%s'%(n,i)].value))))*
                    (1+scipy.special.erf(((x-(params['cen%s_%s'%(n,i)].value))-(np.square((params['sig%s_%s'%(n,i)].value))*
                    (params['dec%s_%s'%(n,i)].value)))/(np.sqrt(2)*(params['sig%s_%s'%(n,i)].value)))) for n in range(N) for i in wav 
                    ])
            )
    fnct=fnct/fnct.max()
    return fnct
    # =============================================================================
    #  this global fit were adapted from  https://stackoverflow.com/questions/20339234/python-and-lmfit-how-to-fit-multiple-datasets-with-shared-parameters/20341726#20341726

    # it is of very important thet we can identify the shared parameteres for datasets
    # =============================================================================


def objective(params, x, data):
    """ calculate total residual for fits to several data sets"""
    ndata = data.shape[0]
    resid = 0.0*data[:]
    # make residual per data set
    resid = data- CONVSum(x,params)
    # now flatten this to a 1D array, as minimize() needs
    return resid.flatten()


# selec datasets
x  = df[949].index
data =df[949].values


# create required sets of parameters, one per data set
N=4 #number of exponential decays
wav=[949]  #the desired data to be fitted
fit_params = Parameters()
for i in wav:
        for n in range(N):
            fit_params.add( 'amp%s_%s'%(n,i), value=1, min=0.0,  max=1)
            fit_params.add( 'dec%s_%s'%(n,i), value=0.5, min=-1e10,  max=1e10)
            fit_params.add( 'cen%s_%s'%(n,i), value=0.1, min=-3.0,  max=1000)
            fit_params.add( 'sig%s_%s'%(n,i), value=0.1, min=0.05, max=0.5)

# now we constrain some values to have the same value
# for example assigning sig_2, sig_3, .. sig_5 to be equal to sig_1
for i in wav:
        for n in (1,2,3):
            print(n,i)
            fit_params['sig%s_%s'%(n,i)].expr='sig0_949'
            fit_params['cen%s_%s'%(n,i)].expr='cen0_949'

# it will run the global fit to all the data sets
result = minimize(objective, fit_params, args=(x,data)) 
report_fit(result.params)

# plot the data sets and fits
plt.close('all')
plt.figure()
for i in wav:
    y_fit = CONVSum(x,result.params)
    plt.plot(x, data, 'o-', x, y_fit, '-')
    plt.xscale('symlog') 
plt.show()

fitted data with convolution of multi exponential and gausian

不幸的是,拟合的结果不是很令人满意,我仍在寻找一些建议来改进这一点。

【讨论】:

  • 这很难阅读并且显然不完整...如果您想帮助清理它并了解如何使其变得更好,请发布一个完整的示例,包括数据的导入和读取。事实上,基本上不可能知道自己在做什么......这对任何人都没有帮助。
猜你喜欢
  • 2016-10-09
  • 2012-12-30
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
相关资源
最近更新 更多