# Tutorial¶

## Simple Example¶

The example below shows how easy it is to define a model that we could fit to.

```
from symfit.api import Parameter, Variable
a = Parameter()
b = Parameter()
x = Variable()
model = a * x + b
```

Lets fit this model to some generated data.

```
from symfit.api import Fit
import numpy as np
xdata = np.linspace(0, 100, 100) # From 0 to 100 in 100 steps
a_vec = np.random.normal(15.0, scale=2.0, size=(100,))
b_vec = np.random.normal(100.0, scale=2.0, size=(100,))
ydata = a_vec * xdata + b_vec # Point scattered around the line 5 * x + 105
fit = Fit(model, xdata, ydata)
fit_result = fit.execute()
```

Printing `fit_result`

will give a full report on the values for every parameter, including the uncertainty, and quality of the fit.

## Initial Guess¶

For fitting to work as desired you should always give a good initial guess for a parameter.
The `Parameter`

object can therefore be initiated with the following keywords:

`value`

the initial guess value.`min`

Minimal value for the parameter.`max`

Maximal value for the parameter.`fixed`

Fix the value of the parameter during the fitting to`value`

.

In the example above, we might change our `Parameter`

‘s to the following after looking at a plot of the data:

```
k = Parameter(value=4, min=3, max=6)
l, m = parameters('b, c')
l.value = 60
l.fixed = True
```

## Accessing the Results¶

A call to `Fit.execute()`

returns a `FitResults`

instance.
This object holds all information about the fit.
The fitting process does not modify the `Parameter`

objects.
In the above example, `k.value`

will still be `4.0`

and not the value we obtain after fitting. To get the value of fit parameters we can do:

```
>>> print(fit_result.params.a)
>>> 14.66946...
>>> print(fit_result.params.a_stdev)
>>> 0.3367571...
>>> print(fit_result.params.b)
>>> 104.6558...
>>> print(fit_result.params.b_stdev)
>>> 19.49172...
>>> print(fit_result.r_squared)
>>> 0.950890866472
```

For more FitResults, see the API docs.

## Evaluating the Model¶

With these parameters, we could now evaluate the model with these parameters so we can make a plot of it. In order to do this, we simply call the model with these values:

```
import matplotlib.pyplot as plt
y = model(x=xdata, a=fit_result.params.a, b=fit_result.params.b)
plt.plot(xdata, y)
plt.show()
```

The model *has* to be called by keyword arguments to prevent any ambiguity. So the following does not work:

```
y = model(xdata, fit_result.params.a, fit_result.params.b)
```

To make life easier, there is a nice shorthand notation to immediately use a fit result:

```
y = model(x=xdata, **fit_result.params)
```

This unpacks the .params object as a dict. For more info view ParameterDict.

## Named Models¶

More complicated models are also relatively easy to deal with by using named models. Let’s try our luck with a bivariate normal distribution:

```
from symfit import parameters, variables, exp, pi, sqrt
x, y, p = variables('x, y, p')
mu_x, mu_y, sig_x, sig_y, rho = parameters('mu_x, mu_y, sig_x, sig_y, rho')
z = (x - mu_x)**2/sig_x**2 + (y - mu_y)**2/sig_y**2 - 2 * rho * (x - mu_x) * (y - mu_y)/(sig_x * sig_y)
model = {p: exp(- z / (2 * (1 - rho**2))) / (2 * pi * sig_x * sig_y * sqrt(1 - rho**2))}
fit = Fit(model, x=xdata, y=ydata, p=pdata)
```

By using the magic of named models, the flow of information is still very clear, even with such a complicated function.

This syntax also supports vector valued functions:

```
model = {y_1: a * x**2, y_2: 2 * x * b}
```

One thing to note about such models is that now `model(x=xdata)`

obviously no longer works as `type(model) == dict`

.
There is a prevered way to resolve this. If any kind of fitting object has been initiated, it will have a `.model`

atribute
containing an instance of `Model`

. This can again be called:

```
model = {y_1: a * x**2, y_2: 2 * x * b}
fit = Fit(model, x=xdata)
fit_result = fit.execute()
y_1, y_2 = fit.model(x=xdata, **fit_result.params)
```

This returns a tuple with the components evaluated so through the magic of tuple unpacking``y_1`` and `y_2`

contain the
evaluated fit. Nice!

If for some reason no `Fit`

is initiated you can make a Model object yourself:

```
from symfit import Model
model_dict = {y_1: a * x**2, y_2: 2 * x * b}
model = Model.from_dict(model_dict)
y_1, y_2 = fit.model(x=xdata, a=2.4, b=0.1)
```

## symfit exposes sympy.api¶

`symfit`

exposes the sympy api as well, so mathematical expressions such as `exp`

, `sin`

and `pi`

are importable
from `symfit`

as well. For more, read the sympy docs.