matlab(tdcs): report, switch/case entry, runners, README
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# tDCS reaching study — MATLAB GLM port
|
||||
|
||||
This directory is a MATLAB port of the Python tDCS GLM analysis
|
||||
(`analysis/tdcs_glm.py`, documented in `analysis/METHODS.md`), driven by raw
|
||||
app-export matrices rather than the pre-joined `tdcs_reach_data.csv`. It
|
||||
reproduces the same three models (count level, rate level, learning rate) and
|
||||
the same H2 anchor check / unknown-condition classification, but replaces the
|
||||
Python's population-average GEE with a `fitglme` GLMM (Poisson/Binomial,
|
||||
subject random intercept) — see "GLMM vs GEE" below.
|
||||
|
||||
## Requirements
|
||||
|
||||
- MATLAB R2025b + Statistics and Machine Learning Toolbox.
|
||||
- A license activated at `~/matlab/licenses/license.dat` (already in place in
|
||||
this environment). If MATLAB ever reports it is unlicensed, activate with:
|
||||
|
||||
```
|
||||
~/matlab/bin/activate_matlab.sh
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
- `tdcs_config.m` — curated 12-animal group map, reference group, merge maps.
|
||||
- `tdcs_load_data.m` — parses `raw/raw_success.csv` and `raw/raw_total.csv`
|
||||
(app-export matrix format), joins them, and applies the curated group map.
|
||||
- `tdcs_scenario_data.m` — builds one of the 6 scenarios (merge map + day
|
||||
window), and saves the scenario table to `derived/<scenario>.csv`.
|
||||
- `tdcs_models.m` — fits the count/rate/learning GLMEs, the per-animal
|
||||
Welch/Mann-Whitney tests, the H2 anchor check, and (unmerged scenarios
|
||||
only) the unknown-condition classification.
|
||||
- `tdcs_report.m` — prints descriptives, the raw GLME fixed-effects tables,
|
||||
and an interpretation section (H2 verdict, per-animal p-values,
|
||||
classification, caveats); also writes `results/<scenario>.txt`.
|
||||
- `tdcs_glm.m` — the entry point: `tdcs_glm(scenario)` runs
|
||||
`tdcs_scenario_data` → `tdcs_models` → `tdcs_report` for one named
|
||||
scenario, via an explicit `switch/case` over all 6 scenario names.
|
||||
- `run_all.m` — runs all 6 scenarios in one script.
|
||||
- `run_tests.m` — runs the `matlab.unittest` suite in `tests/` and exits
|
||||
nonzero on any failure.
|
||||
- `tests/` — `matlab.unittest` test classes (`tLoadData`, `tScenarioData`,
|
||||
`tModels`) with golden values cross-checked against the Python.
|
||||
- `raw/` — pre-generated app-export CSVs (input; not modified by this code).
|
||||
- `derived/` — scenario tables written by `tdcs_scenario_data` (generated).
|
||||
- `results/` — report text files written by `tdcs_report`/`tdcs_glm`
|
||||
(generated).
|
||||
|
||||
## Running
|
||||
|
||||
Run one scenario (valid names: `unmerged_full`, `unmerged_d0_10`,
|
||||
`mergeA2_full`, `mergeA2_d0_10`, `mergeB2_full`, `mergeB2_d0_10`):
|
||||
|
||||
```
|
||||
cd analysis/matlab
|
||||
~/matlab/bin/matlab -batch "addpath(pwd); tdcs_glm('mergeB2_full')"
|
||||
```
|
||||
|
||||
This prints the full report to the console and writes it to
|
||||
`results/mergeB2_full.txt`.
|
||||
|
||||
Run all 6 scenarios:
|
||||
|
||||
```
|
||||
~/matlab/bin/matlab -batch "addpath(pwd); run_all"
|
||||
```
|
||||
|
||||
Run the test suite:
|
||||
|
||||
```
|
||||
~/matlab/bin/matlab -batch "addpath(pwd); run_tests"
|
||||
```
|
||||
|
||||
(`run_tests` calls `error(...)` on any failure, so the `matlab -batch`
|
||||
process exits with a nonzero status — suitable for CI.)
|
||||
|
||||
## Validation against the Python
|
||||
|
||||
Per-animal statistics (per-subject Welch t-test / one-sided Mann-Whitney U,
|
||||
Box-B2 vs Box-A2) are pure stats independent of the GLM choice, and were
|
||||
matched to the Python's golden values to 3 decimals across all 6 scenarios
|
||||
(see `docs/superpowers/plans/2026-07-20-matlab-tdcs-analysis.md`, Task 3).
|
||||
|
||||
## GLMM vs GEE (read this before comparing numbers to the Python)
|
||||
|
||||
The Python reference uses **GEE** (population-average effects, exchangeable
|
||||
working correlation, robust/sandwich SEs) for the count and learning-rate
|
||||
models, and a cluster-robust Binomial GLM for the rate model. This MATLAB
|
||||
port instead uses **GLMM** (`fitglme`, subject-specific effects via a
|
||||
`(1|subject)` random intercept, Laplace/PL approximation) for all three
|
||||
models, because MATLAB's Statistics and Machine Learning Toolbox has no GEE
|
||||
implementation.
|
||||
|
||||
GLMM and GEE estimate related but distinct quantities (subject-specific vs.
|
||||
population-average effects), so **exact coefficients, ratios, and p-values
|
||||
will differ** between the two implementations — sometimes by a fair amount
|
||||
for the small, unbalanced groups in this study. What should agree is the
|
||||
**interpretation**: the direction of the H2 anchor effect, which unknown
|
||||
condition classifies as A2-like/B2-like/ambiguous, and whether the learning
|
||||
rates differ across groups. Treat the MATLAB numbers as a sensitivity check
|
||||
on the Python's conclusions, not as a numerically-identical reproduction.
|
||||
Reference in New Issue
Block a user