Ordinary least squares and linear mixed-effects: minimal examples

OLS and mixed-effect models are specified by model formulas. The results returned by statstmodels for OLS and lme4::lmer for mixed-effcts models populate the FitGrid object. The FitGrid[times, channels] can be sliced by times or channels with pandas index slicing. The results are accessed via the fit object attributes and returned as a pandas.DataFrame or another FitGrid[times, channels].

Generate simulated data and load Epochs

import fitgrid

epochs_df = fitgrid.generate(
    n_samples=6, n_channels=4, return_type="dataframe"
)
epochs_df.set_index(["epoch_id", "time"], inplace=True)
epochs_fg = fitgrid.epochs_from_dataframe(
    epochs_df,
    epoch_id="epoch_id",
    time="time",
    channels=["channel0", "channel1"],
)

Ordinary least squares (OLS)

These models are specified with patsy Python formulas like lm in R. The results come back via statsmodels as FitGrid[times, channels] objects populated with linear_model.RegressionResults.

lm_grid = fitgrid.lm(epochs_fg, RHS='1 + categorical + continuous', quiet=True)

Query and display OLS parameters

channel0 channel1
time
0 Intercept 20.650048 5.585524
categorical[T.cat1] -35.120682 6.599356
continuous -14.775001 -9.338461
1 Intercept 0.683811 -12.571311
categorical[T.cat1] -5.206154 -21.539669
continuous -35.775448 45.342606
2 Intercept -12.530338 11.251361
categorical[T.cat1] 14.008110 -13.685990
continuous 10.068809 12.267045
3 Intercept 12.766953 21.057617
categorical[T.cat1] -18.569296 8.686739
continuous 3.264109 -51.767878
4 Intercept -6.559106 -5.279575
categorical[T.cat1] 12.145254 3.802076
continuous -25.433041 36.160998
5 Intercept 17.456711 -14.128496
categorical[T.cat1] 6.525926 0.118656
continuous -41.083032 26.952374


Query and display parameter standard errors

channel0 channel1
time
0 Intercept 12.552213 12.402446
categorical[T.cat1] 12.901155 12.747224
continuous 22.928736 22.655161
1 Intercept 13.916252 15.612712
categorical[T.cat1] 15.399735 17.277039
continuous 30.691683 34.433151
2 Intercept 13.398024 15.459433
categorical[T.cat1] 16.387789 18.909201
continuous 27.346612 31.554138
3 Intercept 14.410638 13.244376
categorical[T.cat1] 13.168739 12.102985
continuous 21.257582 19.537192
4 Intercept 13.998653 15.979570
categorical[T.cat1] 12.407299 14.163028
continuous 24.230742 27.659579
5 Intercept 17.236837 18.165900
categorical[T.cat1] 14.679198 15.470405
continuous 25.211903 26.570821


params = lm_grid.params
params.index = params.index.set_names(["time", "params"])
for param, vals in params.groupby("params"):
    ax = vals.reset_index("params", drop=True).plot()
    ax.set_title(param)
  • Intercept
  • categorical[T.cat1]
  • continuous

Linear mixed effects (LMER)

These models are specified with lme4::lmer R formulas and the results come back via pymer4 as FitGrid[times, channels] objects populated with Lmer objects from the lme4::lmer and lmerTest results.

Fit a mixed-effects model with lme4::lmer via pymer4

lmer_grid = fitgrid.lmer(
    epochs_fg, RHS='1 + continuous + (continuous | categorical)', quiet=True
)

Out:

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

boundary (singular) fit: see ?isSingular

Query and display some lme4::lmer fit results

channel0 channel1
time
0 (Intercept) Estimate 3.50231 9.06438
2.5_ci -24.8492 -10.9472
97.5_ci 31.8539 29.0759
SE 14.4653 10.2102
DF 1.32568 18
... ... ... ... ...
5 continuous SE 24.4753 36.2556
DF 18 0.867252
T-stat -1.62512 0.578611
P-val 0.121517 0.677492
Sig

96 rows × 2 columns



Total running time of the script: ( 0 minutes 6.046 seconds)

Gallery generated by Sphinx-Gallery