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:
Experiments DB Dev
2026-07-22 15:45:19 -04:00
parent 5fcd97f81a
commit 8a18c894dd
77 changed files with 2066 additions and 345 deletions
+21 -21
View File
@@ -1,21 +1,21 @@
variation,grouping,window,nRats,nObs,covEqual,interaction_p,interaction_est,stim_p,day_p
unmerge_d0_10,unmerge,d0_10,6,61,1,0.142831730250263,1.55766564374789,0.497389134925754,2.83166776054496e-14
unmerge_d0_13,unmerge,d0_13,6,70,1,0.1037612192755,1.54665472676189,0.343602740986316,3.0346358823857e-13
unmerge_d0_5,unmerge,d0_5,6,36,1,0.015149263054839,5.36190476190475,0.688839435920596,1.57055423419133e-07
unmerge_d6_10,unmerge,d6_10,5,25,1,0.485980598616448,1.76666666666666,0.0975215172907211,0.227259314093653
unmerge_d6_13,unmerge,d6_13,5,34,1,0.0971009786566259,2.26696773140328,0.101395665857404,0.117493504965036
right_only_d0_10,right_only,d0_10,7,72,1,0.072180139606096,1.73004431141938,0.715879551990348,5.94289273347193e-16
right_only_d0_13,right_only,d0_13,7,84,1,0.0480416099228058,1.7001712792199,0.528517264593511,1.17078898575779e-14
right_only_d0_5,right_only,d0_5,7,42,1,0.00589730538358453,5.30714285714286,0.469556667463413,1.45827052706827e-08
right_only_d6_10,right_only,d6_10,6,30,1,0.288979620167748,2.425,0.119238243812818,0.200957769624237
right_only_d6_13,right_only,d6_13,6,42,1,0.0258497485171371,2.75792254325755,0.109557181635453,0.0976080018855909
naive_a2_d0_10,naive_a2,d0_10,10,104,1,0.125891264174292,1.43371876298297,0.141836960529428,1.59796354184479e-27
naive_a2_d0_13,naive_a2,d0_13,10,124,1,0.0397967517409217,1.61366204723722,0.153633906173184,2.5469330031931e-28
naive_a2_d0_5,naive_a2,d0_5,10,59,1,0.00107331575782455,6.96223661591522,0.960550975833492,1.1254222201539e-09
naive_a2_d6_10,naive_a2,d6_10,9,45,1,0.449922139297732,-1.8,0.00929038977362001,8.02730473236241e-05
naive_a2_d6_13,naive_a2,d6_13,9,65,1,0.439759713746994,1.15527349799111,0.0165675905421826,0.00123453301903328
naive_boxa_d0_10,naive_boxa,d0_10,11,115,1,0.194116831474294,1.17792772470162,0.124842156542362,1.7431506758907e-32
naive_boxa_d0_13,naive_boxa,d0_13,11,138,1,0.0848056366333164,1.30637615965008,0.140502409490992,1.21292542612342e-34
naive_boxa_d0_5,naive_boxa,d0_5,11,65,1,0.00254470765200637,6.40329932104724,0.881419104187055,2.50618640106882e-11
naive_boxa_d6_10,naive_boxa,d6_10,10,50,1,0.46817073850354,-1.61904761904762,0.014689379915428,1.87688778586107e-05
naive_boxa_d6_13,naive_boxa,d6_13,10,73,1,0.530807487326757,0.873689202983884,0.0303916991304334,6.44631091768978e-05
variation,grouping,window,nRats,nObs,covEqual,interaction_p,interaction_p_satt,interaction_p_rs,interaction_est,stim_p,day_p
unmerge_d0_10,unmerge,d0_10,6,61,1,0.142831730250263,0.142797566084653,0.247946685371652,1.55766564374789,0.497389134925754,2.83166776054496e-14
unmerge_d0_13,unmerge,d0_13,6,70,1,0.1037612192755,0.103490077847449,0.222686826261486,1.54665472676189,0.343602740986316,3.0346358823857e-13
unmerge_d0_5,unmerge,d0_5,6,36,1,0.015149263054839,0.0154996899553134,0.133145634512884,5.36190476190475,0.688839435920596,1.57055423419133e-07
unmerge_d6_10,unmerge,d6_10,5,25,1,0.485980598616448,0.486366669144796,0.554919025308352,1.76666666666666,0.0975215172907211,0.227259314093653
unmerge_d6_13,unmerge,d6_13,5,34,1,0.0971009786566259,0.0970128901807668,0.13816578257917,2.26696773140328,0.101395665857404,0.117493504965036
right_only_d0_10,right_only,d0_10,7,72,1,0.072180139606096,0.0721794737454714,0.124574209202325,1.73004431141938,0.715879551990348,5.94289273347193e-16
right_only_d0_13,right_only,d0_13,7,84,1,0.0480416099228058,0.0478799998667326,0.102857124294903,1.7001712792199,0.528517264593511,1.17078898575779e-14
right_only_d0_5,right_only,d0_5,7,42,1,0.00589730538358453,0.00612750828678172,0.0876259332262465,5.30714285714286,0.469556667463413,1.45827052706827e-08
right_only_d6_10,right_only,d6_10,6,30,1,0.288979620167748,0.289798539517805,0.378365014630273,2.425,0.119238243812818,0.200957769624237
right_only_d6_13,right_only,d6_13,6,42,1,0.0258497485171371,0.0259134063416617,0.0369743190514673,2.75792254325755,0.109557181635453,0.0976080018855909
naive_a2_d0_10,naive_a2,d0_10,10,104,1,0.125891264174292,0.126071775330177,0.30932733005532,1.43371876298297,0.141836960529428,1.59796354184479e-27
naive_a2_d0_13,naive_a2,d0_13,10,124,1,0.0397967517409217,0.0398599319703312,0.0578149015961064,1.61366204723722,0.153633906173184,2.5469330031931e-28
naive_a2_d0_5,naive_a2,d0_5,10,59,1,0.00107331575782455,0.00115218904921896,0.028152310883297,6.96223661591522,0.960550975833492,1.1254222201539e-09
naive_a2_d6_10,naive_a2,d6_10,9,45,1,0.449922139297732,0.450525162691322,0.522263670801849,-1.8,0.00929038977362001,8.02730473236241e-05
naive_a2_d6_13,naive_a2,d6_13,9,65,1,0.439759713746994,0.439915577313227,0.563543413702517,1.15527349799111,0.0165675905421826,0.00123453301903328
naive_boxa_d0_10,naive_boxa,d0_10,11,115,1,0.194116831474294,0.194284662755081,0.383551190839722,1.17792772470162,0.124842156542362,1.7431506758907e-32
naive_boxa_d0_13,naive_boxa,d0_13,11,138,1,0.0848056366333164,0.0848864932608599,0.140324990567599,1.30637615965008,0.140502409490992,1.21292542612342e-34
naive_boxa_d0_5,naive_boxa,d0_5,11,65,1,0.00254470765200637,0.00267934065308424,0.0356145839564805,6.40329932104724,0.881419104187055,2.50618640106882e-11
naive_boxa_d6_10,naive_boxa,d6_10,10,50,1,0.46817073850354,0.468724498567948,0.534407300553877,-1.61904761904762,0.014689379915428,1.87688778586107e-05
naive_boxa_d6_13,naive_boxa,d6_13,10,73,1,0.530807487326757,0.530942127564996,0.696589180707779,0.873689202983884,0.0303916991304334,6.44631091768978e-05
1 variation grouping window nRats nObs covEqual interaction_p interaction_p_satt interaction_p_rs interaction_est stim_p day_p
2 unmerge_d0_10 unmerge d0_10 6 61 1 0.142831730250263 0.142797566084653 0.247946685371652 1.55766564374789 0.497389134925754 2.83166776054496e-14
3 unmerge_d0_13 unmerge d0_13 6 70 1 0.1037612192755 0.103490077847449 0.222686826261486 1.54665472676189 0.343602740986316 3.0346358823857e-13
4 unmerge_d0_5 unmerge d0_5 6 36 1 0.015149263054839 0.0154996899553134 0.133145634512884 5.36190476190475 0.688839435920596 1.57055423419133e-07
5 unmerge_d6_10 unmerge d6_10 5 25 1 0.485980598616448 0.486366669144796 0.554919025308352 1.76666666666666 0.0975215172907211 0.227259314093653
6 unmerge_d6_13 unmerge d6_13 5 34 1 0.0971009786566259 0.0970128901807668 0.13816578257917 2.26696773140328 0.101395665857404 0.117493504965036
7 right_only_d0_10 right_only d0_10 7 72 1 0.072180139606096 0.0721794737454714 0.124574209202325 1.73004431141938 0.715879551990348 5.94289273347193e-16
8 right_only_d0_13 right_only d0_13 7 84 1 0.0480416099228058 0.0478799998667326 0.102857124294903 1.7001712792199 0.528517264593511 1.17078898575779e-14
9 right_only_d0_5 right_only d0_5 7 42 1 0.00589730538358453 0.00612750828678172 0.0876259332262465 5.30714285714286 0.469556667463413 1.45827052706827e-08
10 right_only_d6_10 right_only d6_10 6 30 1 0.288979620167748 0.289798539517805 0.378365014630273 2.425 0.119238243812818 0.200957769624237
11 right_only_d6_13 right_only d6_13 6 42 1 0.0258497485171371 0.0259134063416617 0.0369743190514673 2.75792254325755 0.109557181635453 0.0976080018855909
12 naive_a2_d0_10 naive_a2 d0_10 10 104 1 0.125891264174292 0.126071775330177 0.30932733005532 1.43371876298297 0.141836960529428 1.59796354184479e-27
13 naive_a2_d0_13 naive_a2 d0_13 10 124 1 0.0397967517409217 0.0398599319703312 0.0578149015961064 1.61366204723722 0.153633906173184 2.5469330031931e-28
14 naive_a2_d0_5 naive_a2 d0_5 10 59 1 0.00107331575782455 0.00115218904921896 0.028152310883297 6.96223661591522 0.960550975833492 1.1254222201539e-09
15 naive_a2_d6_10 naive_a2 d6_10 9 45 1 0.449922139297732 0.450525162691322 0.522263670801849 -1.8 0.00929038977362001 8.02730473236241e-05
16 naive_a2_d6_13 naive_a2 d6_13 9 65 1 0.439759713746994 0.439915577313227 0.563543413702517 1.15527349799111 0.0165675905421826 0.00123453301903328
17 naive_boxa_d0_10 naive_boxa d0_10 11 115 1 0.194116831474294 0.194284662755081 0.383551190839722 1.17792772470162 0.124842156542362 1.7431506758907e-32
18 naive_boxa_d0_13 naive_boxa d0_13 11 138 1 0.0848056366333164 0.0848864932608599 0.140324990567599 1.30637615965008 0.140502409490992 1.21292542612342e-34
19 naive_boxa_d0_5 naive_boxa d0_5 11 65 1 0.00254470765200637 0.00267934065308424 0.0356145839564805 6.40329932104724 0.881419104187055 2.50618640106882e-11
20 naive_boxa_d6_10 naive_boxa d6_10 10 50 1 0.46817073850354 0.468724498567948 0.534407300553877 -1.61904761904762 0.014689379915428 1.87688778586107e-05
21 naive_boxa_d6_13 naive_boxa d6_13 10 73 1 0.530807487326757 0.530942127564996 0.696589180707779 0.873689202983884 0.0303916991304334 6.44631091768978e-05
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 8.5397 6.1599 11.839
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(20)= 3.27 F(1)= 10.700 p=0.003822
day (learning) t(20)= 2.89 F(1)= 8.337 p=0.009105
stim (main, window start) t(20)= -1.42 F(1)= 2.025 p=0.1701
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(20)= 3.27 F(1)= 10.700 p=0.003822 p=0.004244 (df=18)
day (learning) t(20)= 2.89 F(1)= 8.337 p=0.009105 p=0.009807 (df=18)
stim (main, window start) t(20)= -1.42 F(1)= 2.025 p=0.1701 p=0.1703 (df=20)
interaction 95% CI: [+3.70, +16.70]
HONEST LME (per-animal random slope, day|rat): interaction F(1,9.8)=9.76, p=0.01107
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.003822, slope diff=+10.20)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 13.78 11.942 15.902
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(100)= 1.54 F(1)= 2.382 p=0.1259
day (learning) t(100)= 15.09 F(1)= 227.710 p=1.598e-27
stim (main, window start) t(100)= 1.48 F(1)= 2.192 p=0.1418
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(100)= 1.54 F(1)= 2.382 p=0.1259 p=0.1261 (df=95)
day (learning) t(100)= 15.09 F(1)=227.710 p=1.598e-27 p=4.059e-27 (df=96)
stim (main, window start) t(100)= 1.48 F(1)= 2.192 p=0.1418 p=0.1543 (df=20)
interaction 95% CI: [-0.41, +3.28]
HONEST LME (per-animal random slope, day|rat): interaction F(1,9.0)=1.16, p=0.3093
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.1259, slope diff=+1.43)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 15.264 13.405 17.381
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(120)= 2.08 F(1)= 4.320 p=0.0398
day (learning) t(120)= 14.57 F(1)= 212.424 p=2.547e-28
stim (main, window start) t(120)= 1.44 F(1)= 2.062 p=0.1536
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(120)= 2.08 F(1)= 4.320 p=0.0398 p=0.03986 (df=117)
day (learning) t(120)= 14.57 F(1)=212.424 p=2.547e-28 p=3.246e-28 (df=119)
stim (main, window start) t(120)= 1.44 F(1)= 2.062 p=0.1536 p=0.1655 (df=21)
interaction 95% CI: [+0.08, +3.15]
HONEST LME (per-animal random slope, day|rat): interaction F(1,41.7)=3.81, p=0.05781
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.0398, slope diff=+1.61)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -34,7 +50,7 @@ if abs(maxT - maxC) > 2
else
cov = '(equal day coverage over this window)';
end
y
ii = gi('day:stim'); pI = C.pValue(ii); eI = C.Estimate(ii);
if pI >= 0.05
verdict = 'n.s. -- slopes parallel (no differential learning rate)';
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -28,27 +28,41 @@ Model fit statistics:
489.28 501.74 -238.64 477.28
Fixed effects coefficients (95% CIs):
Name Estimate SE tStat DF pValue Lower Upper
{'(Intercept)'} 9.0584 5.0267 1.8021 55 0.077018 -1.0153 19.132
{'day' } 8.2568 1.1279 7.3206 55 1.1254e-09 5.9965 10.517
{'stim' } 0.44958 9.048 0.049688 55 0.96055 -17.683 18.582
{'day:stim' } 6.9622 2.0162 3.4532 55 0.0010733 2.9217 11.003
Name Estimate SE tStat DF pValue
{'(Intercept)'} 9.0584 5.0267 1.8021 55 0.077018
{'day' } 8.2568 1.1279 7.3206 55 1.1254e-09
{'stim' } 0.44958 9.048 0.049688 55 0.96055
{'day:stim' } 6.9622 2.0162 3.4532 55 0.0010733
Lower Upper
-1.0153 19.132
5.9965 10.517
-17.683 18.582
2.9217 11.003
Random effects covariance parameters (95% CIs):
Group: rat (10 Levels)
Name1 Name2 Type Estimate Lower Upper
{'(Intercept)'} {'(Intercept)'} {'std'} 9.6432 5.5002 16.907
Name1 Name2 Type Estimate
{'(Intercept)'} {'(Intercept)'} {'std'} 9.6432
Lower Upper
5.5002 16.907
Group: Error
Name Estimate Lower Upper
{'Res Std'} 12.109 9.9317 14.763
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(55)= 3.45 F(1)= 11.924 p=0.001073
day (learning) t(55)= 7.32 F(1)= 53.591 p=1.125e-09
stim (main, window start) t(55)= 0.05 F(1)= 0.002 p=0.9606
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(55)= 3.45 F(1)= 11.924 p=0.001073 p=0.001152 (df=49)
day (learning) t(55)= 7.32 F(1)= 53.591 p=1.125e-09 p=2.092e-09 (df=49)
stim (main, window start) t(55)= 0.05 F(1)= 0.002 p=0.9606 p=0.9609 (df=20)
interaction 95% CI: [+2.92, +11.00]
HONEST LME (per-animal random slope, day|rat): interaction F(1,9.7)=6.65, p=0.02815
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.001073, slope diff=+6.96)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 10.552 8.376 13.294
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(41)= -0.76 F(1)= 0.582 p=0.4499
day (learning) t(41)= 4.38 F(1)= 19.183 p=8.027e-05
stim (main, window start) t(41)= 2.73 F(1)= 7.453 p=0.00929
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(41)= -0.76 F(1)= 0.582 p=0.4499 p=0.4505 (df=36)
day (learning) t(41)= 4.38 F(1)= 19.183 p=8.027e-05 p=9.813e-05 (df=36)
stim (main, window start) t(41)= 2.73 F(1)= 7.453 p=0.00929 p=0.01541 (df=15)
interaction 95% CI: [-6.57, +2.97]
HONEST LME (per-animal random slope, day|rat): interaction F(1,9.0)=0.44, p=0.5223
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.4499, slope diff=-1.80)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 12.033 10.004 14.473
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(61)= 0.78 F(1)= 0.605 p=0.4398
day (learning) t(61)= 3.39 F(1)= 11.485 p=0.001235
stim (main, window start) t(61)= 2.46 F(1)= 6.072 p=0.01657
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(61)= 0.78 F(1)= 0.605 p=0.4398 p=0.4399 (df=58)
day (learning) t(61)= 3.39 F(1)= 11.485 p=0.001235 p=0.001274 (df=57)
stim (main, window start) t(61)= 2.46 F(1)= 6.072 p=0.01657 p=0.02473 (df=17)
interaction 95% CI: [-1.82, +4.13]
HONEST LME (per-animal random slope, day|rat): interaction F(1,7.7)=0.36, p=0.5635
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.4398, slope diff=+1.16)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 13.706 11.962 15.704
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(111)= 1.31 F(1)= 1.707 p=0.1941
day (learning) t(111)= 16.91 F(1)= 285.824 p=1.743e-32
stim (main, window start) t(111)= 1.55 F(1)= 2.392 p=0.1248
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(111)= 1.31 F(1)= 1.707 p=0.1941 p=0.1943 (df=104)
day (learning) t(111)= 16.91 F(1)=285.824 p=1.743e-32 p=6.758e-32 (df=106)
stim (main, window start) t(111)= 1.55 F(1)= 2.392 p=0.1248 p=0.1361 (df=22)
interaction 95% CI: [-0.61, +2.96]
HONEST LME (per-animal random slope, day|rat): interaction F(1,10.1)=0.83, p=0.3836
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.1941, slope diff=+1.18)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 15.18 13.424 17.167
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(134)= 1.74 F(1)= 3.015 p=0.08481
day (learning) t(134)= 16.74 F(1)= 280.201 p=1.213e-34
stim (main, window start) t(134)= 1.48 F(1)= 2.198 p=0.1405
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(134)= 1.74 F(1)= 3.015 p=0.08481 p=0.08489 (df=129)
day (learning) t(134)= 16.74 F(1)=280.201 p=1.213e-34 p=2.161e-34 (df=131)
stim (main, window start) t(134)= 1.48 F(1)= 2.198 p=0.1405 p=0.1519 (df=23)
interaction 95% CI: [-0.18, +2.79]
HONEST LME (per-animal random slope, day|rat): interaction F(1,25.3)=2.32, p=0.1403
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.08481, slope diff=+1.31)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 12.477 10.33 15.071
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(61)= 3.15 F(1)= 9.909 p=0.002545
day (learning) t(61)= 8.14 F(1)= 66.293 p=2.506e-11
stim (main, window start) t(61)= 0.15 F(1)= 0.022 p=0.8814
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(61)= 3.15 F(1)= 9.909 p=0.002545 p=0.002679 (df=54)
day (learning) t(61)= 8.14 F(1)= 66.293 p=2.506e-11 p=5.765e-11 (df=54)
stim (main, window start) t(61)= 0.15 F(1)= 0.022 p=0.8814 p=0.8822 (df=24)
interaction 95% CI: [+2.34, +10.47]
HONEST LME (per-animal random slope, day|rat): interaction F(1,10.5)=5.80, p=0.03561
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.002545, slope diff=+6.40)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 10.142 8.1466 12.627
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(46)= -0.73 F(1)= 0.535 p=0.4682
day (learning) t(46)= 4.77 F(1)= 22.779 p=1.877e-05
stim (main, window start) t(46)= 2.54 F(1)= 6.429 p=0.01469
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(46)= -0.73 F(1)= 0.535 p=0.4682 p=0.4687 (df=40)
day (learning) t(46)= 4.77 F(1)= 22.779 p=1.877e-05 p=2.436e-05 (df=40)
stim (main, window start) t(46)= 2.54 F(1)= 6.429 p=0.01469 p=0.02198 (df=16)
interaction 95% CI: [-6.07, +2.84]
HONEST LME (per-animal random slope, day|rat): interaction F(1,10.0)=0.41, p=0.5344
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.4682, slope diff=-1.62)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 11.525 9.6827 13.718
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(69)= 0.63 F(1)= 0.397 p=0.5308
day (learning) t(69)= 4.26 F(1)= 18.109 p=6.446e-05
stim (main, window start) t(69)= 2.21 F(1)= 4.886 p=0.03039
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(69)= 0.63 F(1)= 0.397 p=0.5308 p=0.5309 (df=65)
day (learning) t(69)= 4.26 F(1)= 18.109 p=6.446e-05 p=6.931e-05 (df=64)
stim (main, window start) t(69)= 2.21 F(1)= 4.886 p=0.03039 p=0.0412 (df=17)
interaction 95% CI: [-1.89, +3.64]
HONEST LME (per-animal random slope, day|rat): interaction F(1,8.5)=0.16, p=0.6966
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.5308, slope diff=+0.87)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 4.4892 4.0771 4.9429
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(227)= 2.66 F(1)= 7.088 p=0.008315
day (learning) t(227)= 8.94 F(1)= 79.838 p=1.43e-16
stim (main, window start) t(227)= 0.92 F(1)= 0.839 p=0.3606
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(227)= 2.66 F(1)= 7.088 p=0.008315 p=0.008365 (df=208)
day (learning) t(227)= 8.94 F(1)= 79.838 p=1.43e-16 p=2.16e-16 (df=209)
stim (main, window start) t(227)= 0.92 F(1)= 0.839 p=0.3606 p=0.3656 (df=37)
interaction 95% CI: [+0.15, +0.97]
HONEST LME (per-animal random slope, day|rat): interaction F(1,24.0)=3.01, p=0.09541
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.008315, slope diff=+0.56)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 11.956 10.063 14.205
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(68)= 1.83 F(1)= 3.336 p=0.07218
day (learning) t(68)= 10.55 F(1)= 111.222 p=5.943e-16
stim (main, window start) t(68)= 0.37 F(1)= 0.134 p=0.7159
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(68)= 1.83 F(1)= 3.336 p=0.07218 p=0.07218 (df=68)
day (learning) t(68)= 10.55 F(1)=111.222 p=5.943e-16 p=4.533e-16 (df=70)
stim (main, window start) t(68)= 0.37 F(1)= 0.134 p=0.7159 p=0.7187 (df=19)
interaction 95% CI: [-0.16, +3.62]
HONEST LME (per-animal random slope, day|rat): interaction F(1,20.5)=2.56, p=0.1246
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.07218, slope diff=+1.73)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 14.12 12.139 16.425
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(80)= 2.01 F(1)= 4.031 p=0.04804
day (learning) t(80)= 9.45 F(1)= 89.224 p=1.171e-14
stim (main, window start) t(80)= 0.63 F(1)= 0.401 p=0.5285
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(80)= 2.01 F(1)= 4.031 p=0.04804 p=0.04788 (df=84)
day (learning) t(80)= 9.45 F(1)= 89.224 p=1.171e-14 p=7.518e-15 (df=84)
stim (main, window start) t(80)= 0.63 F(1)= 0.401 p=0.5285 p=0.5284 (df=84)
interaction 95% CI: [+0.02, +3.39]
HONEST LME (per-animal random slope, day|rat): interaction F(1,20.2)=2.92, p=0.1029
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.04804, slope diff=+1.70)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 9.9638 7.8829 12.594
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(38)= 2.92 F(1)= 8.511 p=0.005897
day (learning) t(38)= 7.17 F(1)= 51.382 p=1.458e-08
stim (main, window start) t(38)= -0.73 F(1)= 0.534 p=0.4696
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(38)= 2.92 F(1)= 8.511 p=0.005897 p=0.006128 (df=35)
day (learning) t(38)= 7.17 F(1)= 51.382 p=1.458e-08 p=2.321e-08 (df=35)
stim (main, window start) t(38)= -0.73 F(1)= 0.534 p=0.4696 p=0.4735 (df=20)
interaction 95% CI: [+1.62, +8.99]
HONEST LME (per-animal random slope, day|rat): interaction F(1,7.0)=3.94, p=0.08763
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.005897, slope diff=+5.31)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 8.1802 6.1646 10.855
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(26)= 1.08 F(1)= 1.172 p=0.289
day (learning) t(26)= 1.31 F(1)= 1.722 p=0.201
stim (main, window start) t(26)= 1.61 F(1)= 2.596 p=0.1192
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(26)= 1.08 F(1)= 1.172 p=0.289 p=0.2898 (df=24)
day (learning) t(26)= 1.31 F(1)= 1.722 p=0.201 p=0.2019 (df=24)
stim (main, window start) t(26)= 1.61 F(1)= 2.596 p=0.1192 p=0.1297 (df=14)
interaction 95% CI: [-2.18, +7.03]
HONEST LME (per-animal random slope, day|rat): interaction F(1,6.0)=0.90, p=0.3784
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.289, slope diff=+2.42)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 7.3669 5.8525 9.2731
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(38)= 2.32 F(1)= 5.379 p=0.02585
day (learning) t(38)= 1.70 F(1)= 2.885 p=0.09761
stim (main, window start) t(38)= 1.64 F(1)= 2.685 p=0.1096
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(38)= 2.32 F(1)= 5.379 p=0.02585 p=0.02591 (df=38)
day (learning) t(38)= 1.70 F(1)= 2.885 p=0.09761 p=0.09766 (df=38)
stim (main, window start) t(38)= 1.64 F(1)= 2.685 p=0.1096 p=0.1304 (df=11)
interaction 95% CI: [+0.35, +5.17]
HONEST LME (per-animal random slope, day|rat): interaction F(1,21.2)=4.96, p=0.03697
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.02585, slope diff=+2.76)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 12.508 10.37 15.086
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(57)= 1.49 F(1)= 2.208 p=0.1428
day (learning) t(57)= 10.08 F(1)= 101.556 p=2.832e-14
stim (main, window start) t(57)= 0.68 F(1)= 0.466 p=0.4974
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(57)= 1.49 F(1)= 2.208 p=0.1428 p=0.1428 (df=57)
day (learning) t(57)= 10.08 F(1)=101.556 p=2.832e-14 p=1.931e-14 (df=59)
stim (main, window start) t(57)= 0.68 F(1)= 0.466 p=0.4974 p=0.5037 (df=17)
interaction 95% CI: [-0.54, +3.66]
HONEST LME (per-animal random slope, day|rat): interaction F(1,13.0)=1.46, p=0.2479
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.1428, slope diff=+1.56)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 14.676 12.436 17.32
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(66)= 1.65 F(1)= 2.721 p=0.1038
day (learning) t(66)= 9.09 F(1)= 82.593 p=3.035e-13
stim (main, window start) t(66)= 0.95 F(1)= 0.910 p=0.3436
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(66)= 1.65 F(1)= 2.721 p=0.1038 p=0.1035 (df=70)
day (learning) t(66)= 9.09 F(1)= 82.593 p=3.035e-13 p=1.823e-13 (df=70)
stim (main, window start) t(66)= 0.95 F(1)= 0.910 p=0.3436 p=0.3434 (df=70)
interaction 95% CI: [-0.33, +3.42]
HONEST LME (per-animal random slope, day|rat): interaction F(1,12.8)=1.64, p=0.2227
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.1038, slope diff=+1.55)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 10.703 8.3104 13.785
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(32)= 2.57 F(1)= 6.588 p=0.01515
day (learning) t(32)= 6.67 F(1)= 44.528 p=1.571e-07
stim (main, window start) t(32)= -0.40 F(1)= 0.163 p=0.6888
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(32)= 2.57 F(1)= 6.588 p=0.01515 p=0.0155 (df=30)
day (learning) t(32)= 6.67 F(1)= 44.528 p=1.571e-07 p=2.162e-07 (df=30)
stim (main, window start) t(32)= -0.40 F(1)= 0.163 p=0.6888 p=0.6906 (df=19)
interaction 95% CI: [+1.11, +9.62]
HONEST LME (per-animal random slope, day|rat): interaction F(1,6.0)=3.02, p=0.1331
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates) (p=0.01515, slope diff=+5.36)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 8.6289 6.3295 11.764
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(21)= 0.71 F(1)= 0.503 p=0.486
day (learning) t(21)= 1.24 F(1)= 1.547 p=0.2273
stim (main, window start) t(21)= 1.73 F(1)= 3.008 p=0.09752
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(21)= 0.71 F(1)= 0.503 p=0.486 p=0.4864 (df=20)
day (learning) t(21)= 1.24 F(1)= 1.547 p=0.2273 p=0.2279 (df=20)
stim (main, window start) t(21)= 1.73 F(1)= 3.008 p=0.09752 p=0.1098 (df=11)
interaction 95% CI: [-3.41, +6.95]
HONEST LME (per-animal random slope, day|rat): interaction F(1,5.0)=0.40, p=0.5549
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.486, slope diff=+1.77)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.
@@ -21,11 +21,27 @@ tbl = table(D.success, D.day - min(D.day), double(D.stim), categorical(D.subject
'VariableNames', {'behavior', 'day', 'stim', 'rat'});
m = fitlme(tbl, 'behavior ~ stim + day + stim:day + (1|rat)');
C = m.Coefficients; A = anova(m); ci = coefCI(m);
As = anova(m, 'DFMethod', 'satterthwaite'); % Satterthwaite denominator DF
% Honest test: refit with a per-animal random SLOPE so the interaction DF
% collapses toward the animal count (guarded -- may not converge in short windows).
rsP = NaN; rsDf = NaN; rsF = NaN; rsOk = false;
wst = warning('off', 'all');
try
mr = fitlme(tbl, 'behavior ~ stim + day + stim:day + (day|rat)');
Ar = anova(mr, 'DFMethod', 'satterthwaite');
ri = strcmp(Ar.Term, 'day:stim');
rsF = Ar.FStat(ri); rsDf = Ar.DF2(ri); rsP = Ar.pValue(ri); rsOk = true;
catch
end
warning(wst);
gi = @(t) find(strcmp(C.Name, t), 1);
ga = @(t) find(strcmp(A.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%8.3f p=%.4g\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)));
gs = @(t) find(strcmp(As.Term, t), 1);
row = @(nm, t) sprintf('%-26s t(%d)=%6.2f F(%d)=%7.3f p=%.4g p=%.4g (df=%.0f)\n', nm, ...
C.DF(gi(t)), C.tStat(gi(t)), A.DF1(ga(t)), A.FStat(ga(t)), C.pValue(gi(t)), ...
As.pValue(gs(t)), As.DF2(gs(t)));
maxT = max(D.day(D.stim == 1)); minT = min(D.day(D.stim == 1));
maxC = max(D.day(D.stim == 0)); minC = min(D.day(D.stim == 0));
@@ -54,11 +70,18 @@ s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim
s = [s sprintf('N = %d rats, %d sessions raw day coverage: treat %d..%d, control %d..%d\n', ...
numel(unique(D.subject)), height(D), minT, maxT, minC, maxC)];
s = [s sprintf('%s\n\n%s\nFULL MODEL SUMMARY -- fitlme\n%s\n%s\n', cov, bar, bar, raw)];
s = [s sprintf('%-26s %-13s %-13s %s\n%s\n', 'effect', 't (df)', 'F (df1)', 'p', repmat('-', 1, 66))];
s = [s sprintf('%-26s %-18s %-12s %s\n%s\n', 'effect', 't(df) / F(df1)', 'p (resid)', 'Satterthwaite: p (df)', repmat('-', 1, 76))];
s = [s row('stim x day (interaction)', 'day:stim')];
s = [s row('day (learning)', 'day')];
s = [s row('stim (main, window start)', 'stim')];
s = [s sprintf('interaction 95%% CI: [%+.2f, %+.2f]\n', ci(ii, 1), ci(ii, 2))];
if rsOk
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): interaction F(1,%.1f)=%.2f, p=%.4g\n', rsDf, rsF, rsP)];
else
s = [s sprintf('HONEST LME (per-animal random slope, day|rat): did not converge for this window.\n')];
end
s = [s sprintf([' (Satterthwaite DF ~= residual on this random-intercept model; the random-slope\n' ...
' model above is the honest learning-rate test -- DF collapses toward the animal count.)\n'])];
s = [s sprintf('INTERPRETATION: stim x day interaction %s (p=%.4g, slope diff=%+.2f)\n', verdict, pI, eI)];
s = [s sprintf('Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.\n')];
@@ -70,5 +93,6 @@ fclose(fid);
% Machine-readable handoff for the summary table (see make_variations.m).
VARRESULT = struct('name', vname, 'nRats', numel(unique(D.subject)), ...
'nObs', height(D), 'interP', pI, 'interEst', eI, ...
'interPsatt', As.pValue(gs('day:stim')), 'interPrs', rsP, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -55,11 +55,14 @@ Group: Error
{'Res Std'} 7.7328 5.9847 9.9914
effect t (df) F (df1) p
------------------------------------------------------------------
stim x day (interaction) t(30)= 1.71 F(1)= 2.933 p=0.0971
day (learning) t(30)= 1.61 F(1)= 2.598 p=0.1175
stim (main, window start) t(30)= 1.69 F(1)= 2.856 p=0.1014
effect t(df) / F(df1) p (resid) Satterthwaite: p (df)
----------------------------------------------------------------------------
stim x day (interaction) t(30)= 1.71 F(1)= 2.933 p=0.0971 p=0.09701 (df=30)
day (learning) t(30)= 1.61 F(1)= 2.598 p=0.1175 p=0.1174 (df=30)
stim (main, window start) t(30)= 1.69 F(1)= 2.856 p=0.1014 p=0.1269 (df=9)
interaction 95% CI: [-0.44, +4.97]
HONEST LME (per-animal random slope, day|rat): interaction F(1,13.9)=2.48, p=0.1382
(Satterthwaite DF ~= residual on this random-intercept model; the random-slope
model above is the honest learning-rate test -- DF collapses toward the animal count.)
INTERPRETATION: stim x day interaction n.s. -- slopes parallel (no differential learning rate) (p=0.0971, slope diff=+2.27)
Paper (N=24): interaction t(227)=2.68, F(1)=7.12, p=0.008.