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:
@@ -30,8 +30,8 @@ s = sprintf('%s\n', bar);
|
||||
s = [s sprintf('PHASED days x tDCS LME -- %s (Box-B2 vs Box-A2)\n', mergeKey)];
|
||||
s = [s sprintf('%s\n', bar)];
|
||||
s = [s sprintf('model per phase: success ~ dayp*tDCS + (1|subject) [dayp = day - phaseStart]\n\n')];
|
||||
s = [s sprintf('%-9s N A2slope B2slope day p tDCS(lvl) p interaction p slopeDiff [95%% CI]\n', 'phase')];
|
||||
s = [s sprintf('%s\n', repmat('-', 1, 92))];
|
||||
s = [s sprintf('%-8s N A2slp B2slp day p tDCS p intP(res) intP(Satt) intP(RS) slopeDiff [95%% CI]\n', 'phase')];
|
||||
s = [s sprintf('%s\n', repmat('-', 1, 104))];
|
||||
|
||||
rawSummaries = '';
|
||||
for k = 1:numel(phases)
|
||||
@@ -42,6 +42,9 @@ for k = 1:numel(phases)
|
||||
|
||||
lme = fitlme(Tp, 'success ~ dayp*tDCS + (1|subject)');
|
||||
C = lme.Coefficients; A = anova(lme); ci = coefCI(lme);
|
||||
As = anova(lme, 'DFMethod', 'satterthwaite');
|
||||
rs = tdcs_random_slope_interaction(Tp, ...
|
||||
'success ~ dayp*tDCS + (dayp|subject)', 'dayp:tDCS');
|
||||
ii = strcmp(C.Name, 'dayp:tDCS');
|
||||
di = strcmp(C.Name, 'dayp');
|
||||
|
||||
@@ -53,22 +56,27 @@ for k = 1:numel(phases)
|
||||
e.dayP = A.pValue(strcmp(A.Term, 'dayp'));
|
||||
e.tDCSlevelP = A.pValue(strcmp(A.Term, 'tDCS'));
|
||||
e.interP = A.pValue(strcmp(A.Term, 'dayp:tDCS'));
|
||||
e.interPsatt = As.pValue(strcmp(As.Term, 'dayp:tDCS')); % Satterthwaite DF
|
||||
e.interPrs = rs.p; e.rsOk = rs.ok; % honest random-slope
|
||||
e.interEst = C.Estimate(ii);
|
||||
e.interCI = ci(ii, :);
|
||||
P.phases{k} = e;
|
||||
|
||||
s = [s sprintf('%d-%-6d %d %6.2f %6.2f %-9.2g %-11.3f %-13.3f %+.2f [%+.2f, %+.2f]\n', ...
|
||||
if rs.ok; rsStr = sprintf('%.3f', rs.p); else; rsStr = 'n/a'; end
|
||||
s = [s sprintf('%d-%-5d %d %5.2f %5.2f %-8.2g %-8.3f %-9.3f %-10.3f %-9s %+.2f [%+.2f,%+.2f]\n', ...
|
||||
ph(1), ph(2), e.nSub, e.a2Slope, e.b2Slope, e.dayP, e.tDCSlevelP, ...
|
||||
e.interP, e.interEst, e.interCI(1), e.interCI(2))]; %#ok<AGROW>
|
||||
e.interP, e.interPsatt, rsStr, e.interEst, e.interCI(1), e.interCI(2))]; %#ok<AGROW>
|
||||
|
||||
rawSummaries = [rawSummaries tdcs_model_summary(lme, ...
|
||||
sprintf('phase %d-%d: success ~ dayp*tDCS + (1|subject)', ph(1), ph(2))) ...
|
||||
sprintf('\n')]; %#ok<AGROW>
|
||||
end
|
||||
|
||||
s = [s sprintf(['\nNote: the interaction p (and CI) use fitlme observation-level DF and are\n' ...
|
||||
'ANTICONSERVATIVE at these small subject counts (see tdcs_power_sim). The early\n' ...
|
||||
'phase carries the Box-B2 faster-acquisition signal; late phases converge.\n'])];
|
||||
s = [s sprintf(['\nColumns: intP(res)=observation-level DF (anticonservative); intP(Satt)=Satterthwaite\n' ...
|
||||
'DF (~= residual on this random-intercept model); intP(RS)=per-animal random-slope\n' ...
|
||||
'(dayp|subject) model, the honest test (DF collapses toward the animal count; ''n/a'' if it\n' ...
|
||||
'did not converge). The early phase carries the Box-B2 faster-acquisition signal; late\n' ...
|
||||
'phases converge.\n'])];
|
||||
|
||||
s = [s rawSummaries];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user