-
Notifications
You must be signed in to change notification settings - Fork 12
4. Fitting
Spinmob provides a nonlinear fitter based on scipy.optimize.leastsq()
. It is capable of fitting arbitrary curves to an arbitrary number of data sets (simutameously), showing the data, curves, and residuals as you go. It also allows you to change the fit range, guess parameters, which parameters are fixed, and more on the fly.
>>> import spinmob as s
>>> f = s.data.fitter(f='a*x*cos(b*x)+c', p='a=0.5, b, c=2')
>>> f
SETTINGS
autoplot True
coarsen [1]
fpoints [1000]
plot_bg [False]
plot_ey [True]
plot_fit [True]
plot_guess [True]
plot_guess_zoom [False]
scale_eydata [1.0]
style_bg [{'color': 'k', 'marker': '', 'ls': '-'}]
style_data [{'color': 'b', 'marker': '+', 'ls': ''}]
style_fit [{'color': 'r', 'marker': '', 'ls': '-'}]
style_guess [{'color': '0.25', 'marker': '', 'ls': '-'}]
subtract_bg [True]
xlabel [None]
xmax [None]
xmin [None]
xscale ['linear']
ylabel [None]
ymax [None]
ymin [None]
yscale ['linear']
CONSTANTS
GUESS
a = 0.5
b = 1.0
c = 2.0
NO DATA
When creating a fitter() instance, you can specify a single function, as shown above, or list of functions (i.e. when fitting multiple data sets), along with a comma-delimited parameter list with (optional) guess values. You can furthermore specify constant parameters and background functions if you like.
Function strings are exposed to all of numpy (e.g. cos
and sqrt
), and you can include your own dictionary of globals via the "g" argument. This is especially useful if you want to define a more complex python function with, e.g., for
loops or something fancy fancy.
All settings, constants, and parameter guesses can be set with either the f.set() or f() function. For example, f(a=3.2, xmin=1, xmax=4)
.
>>> f.set_data(xdata=[1,2,3,4,5], ydata=[1,2,1,4,3], eydata=0.7)
All three arguments can be numpy arrays (Perhaps databox columns? See 2. Data Handling) or lists of numpy arrays (with length matching the number of functions!). Using the default settings, the command above should pop up a plot of the data (blue) and guess (gray):
The way (or whether) these things are plotted can be changed using f.set() as described above. Note for multiple data sets, if you only supply one xdata set, it will assume the same xdata for each ydata set.
>>> f.fit()
This will perform the least-squares minimization, updating the plots and residuals:
You can see the results of the fit on the plot or by again inspecting the f
object as we did in step 1. The output of scipy.optimize.leastsq()
is stored in f.results
. It is a list, the first element is an array of fit parameters, and the second element is the covariance matrix. See the leastsq
documentation for additional info.
Note that if you do not specify the y error bars (eydata) the fitter will make a completely arbitrary guess based on the max and min values of the supplied data. As a result, the reduced chi^2 will be meaningless, the parameter errors / correlations will be totally wrong, and your eyes will eventually cease to smile when your mouth does. You should always estimate and justify your errors, undergrads, because I am grading your reports. However, if you are not my student and you just want a dirty estimate of the error in the fit parameters, you can cheat a bit using f.autoscale_eydata_and_fit() a few times until your reduced chi^2 is 1. Use at your own risk: this basically amounts to estimating the error by sampling the data (which contains the science you are trying to fit!) itself, and assumes that your curve perfectly describes the data and that the errors are totally random, Gaussian, and uncorrelated. Good luck explaining this on a final report, much less how all of your reduced chi^2 values happen to be exactly 1.
You can also specify "background functions" by setting the parameter bg
just as you do for f
. The background function is purely for visualization and has no effect on the fit. For example:
f = s.data.fitter(f='a/(1.0+(x-x0)**2/w**2) + b + c*x',
p='a=1, x0=1, w=1, b=0, c=0',
bg='b+c*x')
f.set_data([1,2,3,4,5,6,7], [1,2,3.5,2,1,0,-1], 0.3)
f.fit()
will produce this:
Notice both the guess and fit functions now display the specified background function, for reference. You can furthermore specify that the background function be subtracted from the data by specifying the setting subtract_bg=False
(in the usual way). The result is then:
Notice the fit background was subtracted from everything, including the guess (which is why the guess is skewed despite c
being 0
). Prior to the fit, the guess background will be subtracted from everything.
Sometimes it is difficult to include the fit function model into a string. Instead of inputting a string to the fitter, you can input a function (which can be quite complex).
As an example we input a simple cosine function.
def cosine_for_fitting(x, a, b, c):
"""
Loud cosine with an offset, 'a*x*cos(b*x)+c'.
"""
for n in range(10): print("Yay!")
return a * x * np.cos(b*x) + c
The fitter takes the function as input. N.B. the fitter currently has the parameters a, b, c set to their default values, which conveniently match the input to the cosine_for_fitting() function. If this were not the case these parameters would need to be changed in the fitter. After initializing the fitter the remaining steps to fit are the same as before.
>>> f = sm.data.fitter(f=cosine_for_fitting)
>>> f.set_data(xdata=[1, 2, 3, 4, 5], ydata=[1.2, 1.4, 1.6, 1.5, 1.2])
>>> f.fit()
These are some of the more commonly used functions when fitting.
-
f.set()
orf()
- allows you to change one or more parameters or settings -
f.ginput()
- click the specified figure to get x,y values (great for guessing!) -
f.trim()
- keeps only the currently visible data for fitting (use the zoom button on the graph!) -
f.zoom()
- zooms out -
f.fix()
- fix one or more of the parameters -
s.tweaks.ubertidy()
- auto-formats figure for Inkscape (use the save button on the graph and save in 'svg' format) -
f(a=11, b=2, plot_guess=False)
- change some guess values and settings (disabling the guess plot) -
f(coarsen=3, subtract_bg=[True, False])
- coarsen the data (by averaging every 4 data points) prior to fitting (```coarsen=0''' means "no coarsening"), and also subtract the background function from only the first data set.
Note when changing a setting, specifying a list allows you to change settings for each plot, and specifying just a value will change the setting for all plots.
Most of the settings are self-explanatory (just try them!), but my favorites are
- coarsen - how much to bin/average the data prior to fitting (0 means "no coarsening")
- xmin, xmax - x-range over which we should actually fit the data
Enjoy!
Up next: 5. Settings, Dialogs, Printing