Fitting the model ================= The first thing you probably want to do after defining a model is fitting it to the observed data. By "fitting" one usually means computing the maximum likelihood estimates of the model parameters :math:`\vec\omega` for the observed data :math:`\vec x_0` (see :doc:`stats` for details). Thus, we have to find values :math:`\hat{\vec\omega}` for the model parameters which minimise the chi-square function. For smooth chi-square functions there are many efficient algorithms which can find *local* minima, but finding the *global* minimum can be rather difficult. myFitter employs a mixed strategy for global optimisation: the parameter space is first explored by random sampling, and then several local optimisations are performed which use the best candidates of the random sample as starting points. There is no guarantee that this method always finds the global minimum, but with a certain amount of tuning it tends to work reliably for most problems. Global minimisations are done in myFitter with the :py:class:`~myFitter.Fitter` class. A :py:class:`~myFitter.Fitter` object can sample a model's parameter space, store the sampled points, and perform local minimisations. For instance, the model from :doc:`models` can be fitted as follows (see also :download:`fit_example.py `): .. _fit-example: .. code-block:: python :linenos: model = MyModel() fitter = Fitter(model) fitter.sample(100) globalmin = fitter.fit(tries=5) In line 1 we create an instance of ``MyModel``, and in line 2 we create a :py:class:`~myFitter.Fitter` object for this model. In line 3 we sample the parameter space with 100 points. myFitter tries to guess reasonable distributions for the model parameters from their ``default``, ``scale`` and ``bounds`` attributes (see :py:class:`~myFitter.Parameter` for details). By default the distributions of the parameters are independent. There are three different ways in which you can modify the sampling distribution of your parameters: 1. Set the :py:attr:`~myFitter.Parameter.generator` attribute of your model parameters to a function of your choice. The function should take zero arguments and return a random value for the parameter. 2. Override the :py:meth:`~myFitter.Model.generateParameterPoint` method of you model class. The method should take zero arguments and return a dictionary with random values for all parameters. 3. Set the `generator` keyword argument of the :py:meth:`~myFitter.Fitter.sample` method to a function of your choice. The function should take zero arguments and return a dictionary with random values for all parameters. Note that options 2 and 3 allow you to implement correlations between your parameters. If you call the :py:meth:`~myFitter.Fitter.sample` method a second time more points are added to the sample, but the old points are not deleted. You can use this to sample a specific region in parameter space with a higher density. Simply adjust the bounds or :py:attr:`~Parameter.generator` attributes of the relevant parameters and sample again. To clear the list of sample points you can use the :py:meth:`~myFitter.Fitter.clear` method. .. _constraint-violation: .. _feasible: .. index:: single: constraint violation single: feasible solution In line 4 we compute the global minimum of the chi-square function by running 5 local minimisations, using the sample points with the 5 lowest chi-square values as starting points. The return value of :py:meth:`Fitter.fit() ` is an instance of :py:class:`~myFitter.FitResult` and stores information about the best solution which was found. The members of :py:class:`~myFitter.FitResult` are: `bestFitParameters` A ``dict`` holding the parameter values at the minimum. `minChiSquare` The chi-square value at the minimum. `constraintViolation` Sum of the squares of the constraint functions for which the constraint is violated. `feasible` Boolean value indicating if the solution has an acceptably small constraint violation. The acceptable level of constraint violation can be set by the `maxcv` argument to :py:meth:`Fitter.fit() ` or :py:func:`~myFitter.fit`. `success` Boolean value indicating if the minimization terminated successfully. `status` Exit code returned by the minimiser. `message` String holding the message returned by the minimizer. `nEvaluations` Number of function evaluations needed to find the minimum. myFitter defines a total ordering for :py:class:`~myFitter.FitResult` objects in the following way: all feasible solutions are smaller than all unfeasible solutions. If two solutions are feasible their :py:attr:`~myFitter.FitResult.minChiSquare` attributes are compared. If two solutions are unfeasible their :py:attr:`~myFitter.FitResult.constraintViolation` attributes are compared. You can therefore compare two :py:class:`~myFitter.FitResult` objects with the operators ``<``, ``==``, ``>`` etc. just as if they were real numbers. The "best" solution returned by :py:meth:`Fitter.fit() ` is the smallest one which was found with respect to this ordering. The :py:class:`~myFitter.FitResult` also defines the ``__str__()`` method, so you can obtain a nice and readable summary of the fit result. For the example from :doc:`models` we get: .. code-block:: python >>> print globalmin best-fit parameters: obs1 syst = 0.0924404116775 p1 = 1.20636170236 p2 = 0.828938775851 minimum chi-square: -9.62023886287 number of evaluations: 8 constraint violation: 0 Optimization terminated successfully. The :py:meth:`Fitter.fit() ` method accepts a number of keyword arguments which let you control the details of the optimisation procedure. The most important ones are: `obs` A dictionary holding the measured values of the observables. Use this to override the values stored in ``model.obs``. `tries` The number of local minimisations to try. `start` A list of ``dict``\ s holding additional starting points for local minimisations. These starting points are tried *in addition* to the ones specified by `tries`. `cvmargin` If your model has :ref:`constraints ` some of the sample points will inevitably violate these constraints. `cvmargin` specifies the maximal amount of :ref:`constraint violation ` a given sample point can have in order to be selected as starting point for a local minimisation. `maxcv` The maximum amount of :ref:`constraint violation ` a solution can have in order to be considered :ref:`feasible `. Defaults to ``1e-4`` `solver` A string which indicates the minimisation algorithm to use. Currently myFitter supports two minimisers from the SciPy package: the COBYLA (``'cobyla'``) algorithm, which is a derivative-free algorithm for constrained optimisation, and the SLSQP (``'slsqp'``) algorithm, which is a gradient search algorithm that can handle non-linear constraints and computes the gradients numerically if necessary. The default setting is ``'slsqp'``, which generally gives the best results for smooth chi-square functions. `solvercfg` A ``dict`` holding configuration options for the solver. Allowed keys depend on the solver, but some options are common to all solvers. These options are: ``'acc'`` Required accuracy of the minimisations. The exact meaning depends on the solver. Defaults to ``1e-5``. ``'maxiter'`` Maximum number of iterations. Defaults to 1000. ``'disp'`` Boolean indicating if information about the minimisation should be printed. Defaults to ``False``. ``'iprint'`` Integer indicating the amount of information to print. Exact meaning depends on the solver. Defaults to 1. The same keyword arguments can also be given to the constructor of :py:class:`~myFitter.Fitter`. In this case the :py:class:`~myFitter.Fitter` object will remember the the specified values and use them as defaults when the :py:meth:`~myFitter.Fitter.fit` method is called. Any keywords passed to :py:meth:`~myFitter.Fitter.fit` directly override the defaults. The local minimisations are actually done by a function called :py:func:`~myFitter.fit`, which is different from and invoked by the method :py:meth:`Fitter.fit() `. Any keyword arguments that :py:meth:`Fitter.fit() ` doesn't recognise are handed down to :py:func:`~myFitter.fit`.