# Choosing between lme/nlme, brms, KFAS, and ctsem

#### Alex Litovchenko

#### 2026-04-17

This vignette is a decision guide, not a technical deep dive. Use it to pick an entry point:

- `ild_lme()` when the main need is multilevel regression with residual temporal correlation (AR1/CAR1, random effects).
- `ild_brms()` when uncertainty, priors, and Bayesian partial pooling across persons matter most.
- `ild_kfas()` when the target is discrete-time latent temporal state estimation (single series per fit).
- `ild_ctsem()` when the target is continuous-time latent dynamics under irregular measurement timing.

## Decision axes

Ask:

1. Population vs single-series focus — Do you need inference for a population of persons (fixed/random effects, WP/BP) or a structured model for one long series (latent level/trend)?
2. Multilevel vs state-space — Is the scientific target between- and within-person structure with residual temporal correlation, or explicit latent dynamics (Kalman smoothing/filtering) for one trajectory?
3. Frequentist vs Bayesian — `ild_lme()` / nlme vs `ild_brms()` (Stan); KFAS in tidyILD is likelihood / ML-oriented for the wrapped fits.
4. Diagnostics — Frequentist/brms: `ild_diagnostics()` / bundle from `ild_diagnose()` for standard models; KFAS: `ild_diagnose()` emphasizes innovations, ACF, and bundle sections tuned for state space (see `?ild_diagnose`).

## Comparison table

| `ild_lme()` (lme4 / nlme) | `ild_brms()` | `ild_kfas()` (KFAS) | `ild_ctsem()` (ctsem)
--- | --- | --- | --- | ---
Typical use | Multilevel regression, AR1/CAR1 on residuals | Hierarchical Bayes, flexible priors | Univariate latent level (v1), single `.ild_id` per fit | Continuous-time latent dynamics with irregular timing
ID structure | Multiple `.ild_id`, random effects | Multiple `.ild_id`, partial pooling | One person per fit (v1); not pooled latent state across IDs | v1 wrapper is conservative (single-series focus)
Temporal structure | Residual AR1/CAR1; spacing-informed choice | Flexible time / residual modeling | Discrete-time local level on observation order | Continuous-time drift/diffusion parameterization
Priors | N/A (frequentist) | Yes (user-specified) | Implicit via likelihood / ML | Depends on ctsem fit mode (`ctStanFit` / `ctFit`)
Predictive checks | Via bundle / extensions | PPC via brms (`pp_check`) | Forecast / innovation plots (not PPC); see `ild_autoplot(bundle)` for KFAS | Bundle diagnostics + ctsem residual/fitted views
Provenance / report | `ild_provenance`, `ild_report` | Same | Same; KFAS stores state spec, smoothing, `fit_context` | Same; ctsem fit type and scaling recorded

Important: `ild_kfas()` is not a drop-in replacement for a multilevel model with person-level random effects. If you fit separate state-space models per person, use `fit_context = "independent_series_per_id"` when that matches your design and read `GR_KFAS_UNMODELED_BETWEEN_PERSON_HETEROGENEITY` and related guardrails.

## Short pointers to other vignettes

- Temporal dynamics and model choice (lags, AR, TVEM vs latent): `vignette("temporal-dynamics-model-choice", package = "tidyILD")`
- Overall workflow: `vignette("tidyILD-workflow", package = "tidyILD")`
- Report-style analysis: `vignette("ild-analysis-report", package = "tidyILD")`
- State-space concepts (KFAS): `vignette("kfas-state-space-modeling", package = "tidyILD")`
- Irregular timing + KFAS: `vignette("kfas-irregular-timing-spacing", package = "tidyILD")`
- Continuous-time ctsem backend: `vignette("ctsem-continuous-time-dynamics", package = "tidyILD")`
- Spacing and WP/BP: `vignette("ild-decomposition-and-spacing", package = "tidyILD")`

## See also

`inst/dev/KFAS_V1_BACKEND.md` (backend scope), `?ild_kfas`, `?ild_ctsem`, `?ild_lme`, `?ild_brms`.