feat(matlab): add Satterthwaite DF + honest random-slope test to LME reports
Every fitlme-based report (lme_*, paper_*, phase_*, and the variations' analyze.m) now shows, per effect: residual-DF p, Satterthwaite-DF p, and -- for the interaction -- an HONEST test from a per-animal random-SLOPE model (day|rat), whose Satterthwaite DF collapses toward the animal count. New: tdcs_random_slope_interaction.m (shared helper). Wired into tdcs_lme, tdcs_paper_lme, tdcs_phase_lme, variation_analyze; SUMMARY.csv gains interaction_p_satt / interaction_p_rs. Regenerated all results/, variations/, matched-effort outputs. Key point this surfaces: Satterthwaite ~= residual on the random-INTERCEPT model (the slope's error is at session level), so it does NOT fix pseudoreplication; the random-slope model does. Effect: full-range mergeA2 interaction 0.009 -> 0.75 (collapses); unmerge_d0_5 0.015 -> 0.13 (n.s.); the pooled-control early windows survive honestly (naive_a2_d0_5 0.001 -> 0.028; naive_boxa_d0_5 0.003 -> 0.036). Suite 42/42. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,12 @@ s = [s sprintf('\n')];
|
||||
|
||||
s = [s tdcs_model_summary(L.lme, 'fitlme: success ~ day*tDCS + (1|subject)') sprintf('\n')];
|
||||
|
||||
s = [s sprintf('%-27s %-14s %-13s %s\n', 'effect', 't (df)', 'F (df1)', 'p')];
|
||||
s = [s sprintf('%s\n', repmat('-', 1, 70))];
|
||||
s = [s sprintf('%-27s %-20s %-12s %s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)')];
|
||||
s = [s sprintf('%s\n', repmat('-', 1, 78))];
|
||||
s = [s localRow('days x tDCS (interaction)', L.interaction)];
|
||||
s = [s localRow('days (learning)', L.day)];
|
||||
s = [s localRow('tDCS (main, at Day 1)', L.tDCS)];
|
||||
s = [s localHonest(L.interRS)];
|
||||
|
||||
s = [s sprintf('\nINTERPRETATION\n')];
|
||||
if L.interaction.p >= 0.05
|
||||
@@ -66,7 +67,24 @@ fprintf(fid, '%s', s);
|
||||
end
|
||||
|
||||
function r = localRow(name, e)
|
||||
r = sprintf('%-27s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', name, e.df, e.t, e.df1, e.F, e.p);
|
||||
r = sprintf('%-27s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', ...
|
||||
name, e.df, e.t, e.df1, e.F, e.p, e.pSatt, e.dfSatt);
|
||||
end
|
||||
|
||||
function s = localHonest(rs)
|
||||
%LOCALHONEST Report the random-slope interaction (the honest LME test) + why
|
||||
% Satterthwaite on the random-intercept model above barely changes the DF.
|
||||
if rs.ok
|
||||
s = sprintf(['\nHONEST LME -- per-animal random slope (day|subject): ' ...
|
||||
'interaction F(%d,%.1f)=%.2f, p=%.4g\n'], rs.df1, rs.df2, rs.F, rs.p);
|
||||
else
|
||||
s = sprintf(['\nHONEST LME -- per-animal random slope (day|subject): ' ...
|
||||
'model did not converge for this window.\n']);
|
||||
end
|
||||
s = [s sprintf([' Note: Satterthwaite DF on the random-INTERCEPT model above stays ~= residual\n' ...
|
||||
' (the slope''s error is at the session level), so it does NOT fix pseudoreplication.\n' ...
|
||||
' Letting each animal have its OWN slope collapses the interaction DF toward the animal\n' ...
|
||||
' count -- this, and the per-animal slope test, are the honest learning-rate inference.\n'])];
|
||||
end
|
||||
|
||||
function t = localSig(p)
|
||||
|
||||
Reference in New Issue
Block a user