tBuLi / symfit

Symbolic Fitting; fitting as it should be.
http://symfit.readthedocs.org
MIT License
232 stars 17 forks source link

Symfit errors - not fitting to data #358

Closed chrismarsden7 closed 1 year ago

chrismarsden7 commented 1 year ago

Hi, I'm trying to use Symfit for the first time to fit a simple parabolic function. I have provided code below to re-create the issue, with the solver not finding a result and throwing up error messages that I don't fully understand. I have generated fake data (xdata,ydata) using exactly the same functional form as the function used to fit said data. The initial guesses I choose seem to have no effect on what the solver is doing.

import numpy as np

# generate example xdata and ydata for error reproduction for public use
xdata = np.linspace(0.0,1.0,101,endpoint=True)
ydata = ( 1.0 - xdata**0.5 )**1.5 * 0.5e+06 * 0.5 / 1.0

import matplotlib.pyplot as plt
plt.plot(xdata,ydata)
plt.show()

from symfit import variables, parameters, Fit

alpha_m, alpha_n, L, beta0, Rax = parameters('alpha_m, alpha_n, L, beta0, Rax')
x, y = variables('x,y')

# Set initial guesses for parameters
alpha_m.value = 1.2
alpha_m.min = 0.1
alpha_m.min = 3.0
alpha_m.fixed = False

alpha_n.value = 1.3
alpha_n.min = 0.1
alpha_n.min = 3.0
alpha_n.fixed = False

L.value = 2.0e+05
L.fixed = False
L.min = 1.0e+05
L.max = 1.0e+06

beta0.value = 0.3
beta0.fixed = False
beta0.min = 0.1
beta0.max = 2.0

Rax.value = 1.0
Rax.fixed = True

y_form = ( 1.0 - x**alpha_m )**alpha_n * L * beta0 / Rax
model_dict = {
    y: y_form
}

fit = Fit(model_dict, x=xdata, y=ydata)
fit_result = fit.execute()
print(fit_result)

Cheers, Chris

pckroon commented 1 year ago

Hi Chris,

the main issue here is that you made 2 typoes in the bounds of alpha_m and alpha_n, rather than define a min/max you define the min twice. However, there's more going on, so I'll keep the response I typed originally down here as well. If you take xdata = np.linspace(1e-16, 1, 101, endpoint=False) (see below) with the appropriate bounds it works.

Happy fitting! Peter


Hi Chris,

I also have issues getting this to work properly :\ There are a few things going on I think, and a workaround at the end. Your model (( 1.0 - x**alpha_m )**alpha_n * L * beta0 / Rax) has a few problematic properties, the first of which is that L, beta0, and Rax are effectively identical (I'm inclined to say colinear, but I'm not 100% sure on the jargon here), meaning that any change/error in one of the three I can be corrected with the others. This will lead to infinite covariances between these variables, and their individual values will be meaningless. Secondly, symfit uses the first (Jacobian) and sometimes second (Hessian) derivatives of your model wrt the parameters. In your model these contain discontinuities:

If you limit your x range to x=0.1 to x=0.9 and fix L to 5e5 the fit already behaves much much better. From there you can either play with the initial guesses, or go for a derivative free minimizer such as Nelder-Mead or Powell (from symfit.core.minimizers import NelderMead, Powell), but those will ignore your bounds (this is where I realized there's an issue with your bounds). Alternatively if it's not cooperating and you're tired of tweaking initial guesses you can try the DifferentialEvolution global minimizer. Will take a bit longer to run the fit though.