# Fitting a model¶

We can fit a model to individual participant data in a free-recall dataset by maximizing the probability of the data according to the model. This involves using a search algorithm to adjust the model parameters until the probability, or likelihood (see Evaluating a model), of the data is maximized.

First, load some sample data to fit:

```
In [1]: from cymr import fit, parameters
In [2]: data = fit.sample_data('Morton2013_mixed').query('subject <= 3')
```

## Search Definition¶

Next, we need to define our search parameters. There are two types of parameters used specifically for searches:

- fixed
Parameters that have a fixed value. These parameters are not searched.

- free
Parameters that may vary to fit a dataset. For a search, must specify a range to be searched over.

We’ll also use two other types of parameters that set properties of the model based on a given parameter set:

- dependent
Parameters that are derived from other parameters. These parameters are specified using an expression that generates them from other parameters.

- weights
Parameters that define weighting of different patterns in the model.

We can organize these things by creating a Parameters object. To run a simple and fast search, we’ll fix almost all parameters and just fit one, \(\beta_\mathrm{enc}\). For a real project, you may want to free other parameters also to fit individual differences in the primacy effect, temporal clustering, etc.

```
In [3]: par = parameters.Parameters()
In [4]: par.set_fixed(T=0.1, Lfc=0.15, Lcf=0.15, P1=0.2, P2=2,
...: B_start=0.3, B_rec=0.9, X1=0.001, X2=0.25)
...:
In [5]: par.set_free(B_enc=(0, 1))
In [6]: par.set_dependent(Dfc='1 - Lfc', Dcf='1 - Lcf')
```

To simulate free recall using the CMR-Distributed model, we must first define pre-experimental weights for the network. For this example, we’ll define localist patterns, which are distinct for each presented item. They can be represented by an identity matrix with one entry for each item. See Evaluating a model for details.

```
In [7]: n_items = 768
In [8]: patterns = {'vector': {'loc': np.eye(n_items)}}
In [9]: par.set_sublayers(f=['task'], c=['task'])
In [10]: weights = {(('task', 'item'), ('task', 'item')): 'loc'}
In [11]: par.set_weights('fc', weights)
In [12]: par.set_weights('cf', weights)
```

We can print the parameter definition to get an overview of the settings.

```
In [13]: print(par)
fixed:
T: 0.1
Lfc: 0.15
Lcf: 0.15
P1: 0.2
P2: 2
B_start: 0.3
B_rec: 0.9
X1: 0.001
X2: 0.25
free:
B_enc: (0, 1)
dependent:
Dfc: 1 - Lfc
Dcf: 1 - Lcf
dynamic:
sublayers:
f: ['task']
c: ['task']
weights:
fc: {(('task', 'item'), ('task', 'item')): 'loc'}
cf: {(('task', 'item'), ('task', 'item')): 'loc'}
sublayer_param:
```

The `to_json()`

method of
`Parameters`

can be used to save out parameter
definitions to a file. The output file uses JSON format, which is
both human- and machine-readable and can be loaded later to restore
search settings:

```
In [14]: par.to_json('parameters.json')
In [15]: restored = parameters.read_json('parameters.json')
```

## Parameter Search¶

Finally, we can run the search. Parameters will be optimized separately for each participant. For speed, we’ll set the tolerance to be pretty high (0.1); normally this should be much lower to ensure that the search converges.

```
In [16]: from cymr import cmr
In [17]: model = cmr.CMRDistributed()
In [18]: results = model.fit_indiv(data, par, patterns=patterns, tol=0.1)
In [19]: results[['B_enc', 'logl', 'n', 'k']]
Out[19]:
B_enc logl n k
subject rep
1 0 0.651311 -958.567150 373.0 1.0
2 0 0.510583 -1113.487677 426.0 1.0
3 0 0.743079 -983.635155 379.0 1.0
```

The results give the complete set of parameters, including fixed parameters, optimized free parameters, and dependent parameters. It also includes fields with statistics relevant to the search:

- logl
Total log likelihood for each participant. Greater (i.e., less negative) values indicate better fit.

- n
Number of data points fit.

- k
Number of free parameters.