I am trying to perform a fitting for my data using the lmfit package. However I couldnt find any built-in model for a multi-exponential decay. I have tried to create my own function, and then to fit it. My code is the following:
import os
import time
import numpy as np
import pandas as pd
import lmfit
from lmfit.models import ExponentialModel, LinearModel
from lmfit import Model, Parameter, report_fit
def MultiExpDecay(tiempo,C1,tau1,C2,tau2):
return C1*np.exp(-tiempo/tau1)+C2*np.exp(-tiempo/tau2)
def MultiExpDecay_fit():
C1s = []
C1s_error = []
C2s = []
C2s_error = []
tau1s = []
tau1s_error = []
tau2s = []
tau2s_error = []
Fit_MultiExpDecays = []
model = Model(MultiExpDecay, independent_vars=['tiempo'])
for c in range(len(V_APD.columns)):
xdat = tiempo.iloc[:, c]
ydat = V_APD.iloc[:, c]
pars = model.guess(ydat, x=xdat)
fit = model.fit(ydat, pars, x=xdat)
fit_values = model.eval(pars, x=xdat)
Fit_MultiExpDecays.append(fit_values)
for key in fit.params:
if key == 'C1':
#print(key, "=", out.params[key].value, "+/-", out.params[key].stderr)
C1s.append(fit.params[key].value)
C1s_error.append(fit.params[key].stderr)
elif key == 'C2':
C2s.append(fit.params[key].value)
C2s_error.append(fit.params[key].stderr)
elif key == 'tau1':
tau1s.append(fit.params[key].value)
tau1s_error.append(fit.params[key].stderr)
elif key == 'tau2':
tau2s.append(fit.params[key].value)
tau2s_error.append(fit.params[key].stderr)
Fit_MultiExpDecays = np.transpose(pd.DataFrame(Fit_MultiExpDecays, index=labels))
C1 = np.transpose(pd.DataFrame(C1s, index = labels, columns = ['C1']))
C2 = np.transpose(pd.DataFrame(C2s, index=labels, columns=['C2']))
tau1 = np.transpose(pd.DataFrame(tau1s, index=labels, columns=['tau1']))
tau2 = np.transpose(pd.DataFrame(tau2s, index=labels, columns=['tau2']))
C1_error = np.transpose(pd.DataFrame(C1s_error, index = labels, columns=['C1 error']))
C2_error = np.transpose(pd.DataFrame(C2s_error, index=labels, columns=['C2 error']))
tau1_error = np.transpose(pd.DataFrame(tau1s_error, index=labels, columns=['tau1 error']))
tau2_error = np.transpose(pd.DataFrame(tau2s_error, index=labels, columns=['tau2 error']))
C1 = pd.concat([C1, C1_error])
C2 = pd.concat([C2, C2_error])
tau1 = pd.concat([tau1, tau1_error])
tau2 = pd.concat([tau2, tau2_error])
return C1, C2, tau1, tau2, Fit_MultiExpDecays
C1, C2, tau1, tau2, Fit_MultiExpDecays = MultiExpDEcay_fit():
An error is raised but cannot identify the problem.
File "C:\ProgramData\Anaconda3\Lib\site-packages\lmfit\model.py", line 737, in guess
raise NotImplementedError(msg)
NotImplementedError: guess() not implemented for Model
You could also use two lmfit.ExponentialModel
, as with
import numpy as np
from lmfit.models import ExponentialModel
def dblexp( x, c1, l1, c2, l2 ):
return c1 * np.exp( -x / l1 ) + c2 * np.exp( -x / l2 )
xl = np.linspace(0, 10, 101)
yl = dblexp(xl, 32.44, 0.81, 11.51, 9.22 ) + np.random.normal(0, 0.2, xl.size)
mymodel = ExponentialModel(prefix='e1_') + ExponentialModel(prefix='e2_')
params = mymodel.make_params(e1_amplitude=10, e1_decay=10,
e2_amplitude=25, e2_decay=0.50)
result = mymodel.fit(yl, params, x=xl)
print( result.fit_report() )
For the actual question: As the exception says, Model
does not know how to guess reasonable parameter values for an arbitrary, user-defined model function - the Model.guess()
method raises this exception by default and must be overwritten by each subclass. lmfit
provides this method for the provided submodels (including ExponentialModel
), but these are each coded with an understanding of those particular models.
Finally: fitting double-exponential decay is notoriously error-prone and difficult for least-squares approaches (or at least Levenberg-Marquardt implementations). For more realistic cases, I would recommend fitting the log of the data with the log of the double-exponential decay.