analysis(matlab): per-variation subfolders (grouping x window) for the paper LME

Add make_variations.m + variation_analyze.m generating 20 self-contained
subfolders under analysis/matlab/variations/, one per grouping x day-window,
each with exactly three files: data.csv (curated subset), analyze.m (a simple
standalone script fitting behavior ~ stim + day + stim:day + (1|rat) on the
success COUNT), and result.txt (its output). Plus variations/SUMMARY.csv.

Groupings (stim=1 / stim=0, other groups dropped):
  unmerge     B2 vs A2
  right_only  B2+Right vs A2            (Box-A dropped)
  naive_a2    B2 vs A2+Naive           (Right, Box-A dropped)
  naive_boxa  B2 vs A2+Naive+Box-A     (Right dropped)
Windows: 0-10, 0-13, 0-5, 6-10, 6-13. All 20 have equal day coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Experiments DB Dev
2026-07-20 20:49:54 -04:00
parent 963fd889b2
commit 969c0205e8
63 changed files with 4343 additions and 0 deletions
@@ -0,0 +1,74 @@
% Variation analysis -- the paper's linear mixed model on the successful-reach
% COUNT, fit on this folder's curated data subset.
%
% model: behavior ~ stim + day + stim:day + (1|rat)
% behavior = successful reaches (count per session)
% stim = 1 for the treatment group(s), 0 for the control group(s)
% day = training day within this window (0 = first analyzed day)
% rat = subject (random intercept)
%
% Self-contained: reads data.csv beside this script and writes result.txt.
% Run headless from this folder with: matlab -batch "analyze"
% (This is a copy of analysis/matlab/variation_analyze.m; see make_variations.m.)
here = fileparts(mfilename('fullpath'));
if isempty(here); here = pwd; end
vname = regexprep(here, '.*[/\\]', ''); % folder name = variation id
D = readtable(fullfile(here, 'data.csv'), 'TextType', 'string');
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);
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)));
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));
if abs(maxT - maxC) > 2
cov = '** WARNING: unequal day coverage -- interaction may be confounded. **';
else
cov = '(equal day coverage over this window)';
end
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)';
elseif eI > 0
verdict = 'SIGNIFICANT positive -- treatment improves FASTER (benefit accumulates)';
else
verdict = 'SIGNIFICANT negative -- treatment improves SLOWER (groups converge)';
end
bar = repmat('=', 1, 78);
raw = regexprep(evalc('disp(m)'), '</?strong>', '');
s = sprintf('%s\nVARIATION: %s\n%s\n', bar, vname, bar);
s = [s sprintf('model: behavior ~ stim + day + stim:day + (1|rat) (behavior = success COUNT)\n')];
s = [s sprintf('day = training day within window (0 = first analyzed day)\n')];
s = [s sprintf('treatment (stim=1): %s\n', strjoin(cellstr(unique(D.group(D.stim == 1))), ', '))];
s = [s sprintf('control (stim=0): %s\n', strjoin(cellstr(unique(D.group(D.stim == 0))), ', '))];
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 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))];
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')];
fprintf('%s', s);
fid = fopen(fullfile(here, 'result.txt'), 'w');
fprintf(fid, '%s', s);
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, ...
'stimP', C.pValue(gi('stim')), 'dayP', C.pValue(gi('day')), ...
'covEqual', abs(maxT - maxC) <= 2);
@@ -0,0 +1,125 @@
subject,group,day,success,total,stim
Banh-mi-1,Electrode-Box-B2,0,13,84,1
Banh-mi-1,Electrode-Box-B2,1,35,86,1
Banh-mi-1,Electrode-Box-B2,2,47,110,1
Banh-mi-1,Electrode-Box-B2,3,65,140,1
Banh-mi-1,Electrode-Box-B2,4,70,127,1
Banh-mi-1,Electrode-Box-B2,5,102,142,1
Banh-mi-1,Electrode-Box-B2,6,90,131,1
Banh-mi-1,Electrode-Box-B2,7,109,148,1
Banh-mi-1,Electrode-Box-B2,8,104,137,1
Banh-mi-1,Electrode-Box-B2,9,119,150,1
Banh-mi-1,Electrode-Box-B2,10,121,158,1
Banh-mi-1,Electrode-Box-B2,11,121,148,1
Banh-mi-1,Electrode-Box-B2,12,120,149,1
Banh-mi-1,Electrode-Box-B2,13,135,154,1
Banh-mi-2,Electrode-Box-A2,0,25,97,0
Banh-mi-2,Electrode-Box-A2,1,22,101,0
Banh-mi-2,Electrode-Box-A2,2,22,119,0
Banh-mi-2,Electrode-Box-A2,3,29,118,0
Banh-mi-2,Electrode-Box-A2,4,27,136,0
Banh-mi-2,Electrode-Box-A2,5,43,146,0
Banh-mi-2,Electrode-Box-A2,6,74,146,0
Banh-mi-2,Electrode-Box-A2,7,70,148,0
Banh-mi-2,Electrode-Box-A2,8,65,130,0
Banh-mi-2,Electrode-Box-A2,9,79,151,0
Banh-mi-2,Electrode-Box-A2,10,93,152,0
Egg-tart-1,Electrode-Box-B2,0,7,56,1
Egg-tart-1,Electrode-Box-B2,1,16,78,1
Egg-tart-1,Electrode-Box-B2,2,23,103,1
Egg-tart-1,Electrode-Box-B2,3,63,120,1
Egg-tart-1,Electrode-Box-B2,4,69,132,1
Egg-tart-1,Electrode-Box-B2,5,83,136,1
Egg-tart-1,Electrode-Box-B2,6,71,142,1
Egg-tart-1,Electrode-Box-B2,7,79,138,1
Egg-tart-1,Electrode-Box-B2,8,98,142,1
Egg-tart-1,Electrode-Box-B2,9,89,139,1
Egg-tart-1,Electrode-Box-B2,10,96,143,1
Egg-tart-1,Electrode-Box-B2,11,96,148,1
Egg-tart-1,Electrode-Box-B2,12,101,156,1
Egg-tart-1,Electrode-Box-B2,13,103,152,1
Egg-tart-2,Electrode-Box-A2,0,9,32,0
Egg-tart-2,Electrode-Box-A2,1,2,38,0
Egg-tart-2,Electrode-Box-A2,2,31,93,0
Egg-tart-2,Electrode-Box-A2,3,44,101,0
Egg-tart-2,Electrode-Box-A2,4,54,131,0
Egg-tart-2,Electrode-Box-A2,5,84,139,0
Egg-tart-2,Electrode-Box-A2,6,85,145,0
Egg-tart-2,Electrode-Box-A2,7,79,143,0
Egg-tart-2,Electrode-Box-A2,8,76,131,0
Egg-tart-2,Electrode-Box-A2,9,88,149,0
Egg-tart-2,Electrode-Box-A2,10,81,151,0
Egg-tart-2,Electrode-Box-A2,11,78,152,0
Egg-tart-2,Electrode-Box-A2,12,96,155,0
Egg-tart-2,Electrode-Box-A2,13,84,155,0
Khoai-lang-2,Naive,0,0,0,0
Khoai-lang-2,Naive,1,0,0,0
Khoai-lang-2,Naive,2,10,47,0
Khoai-lang-2,Naive,3,11,52,0
Khoai-lang-2,Naive,4,9,56,0
Khoai-lang-2,Naive,5,34,95,0
Khoai-lang-2,Naive,6,21,72,0
Khoai-lang-2,Naive,7,23,99,0
Khoai-lang-2,Naive,8,64,136,0
Khoai-lang-2,Naive,9,75,131,0
Khoai-lang-2,Naive,10,63,134,0
Khoai-lang-2,Naive,11,59,139,0
Khoai-lang-2,Naive,12,51,129,0
Khoai-lang-2,Naive,13,73,143,0
Khoai-tay-2,Naive,1,21,68,0
Khoai-tay-2,Naive,2,6,79,0
Khoai-tay-2,Naive,3,0,83,0
Khoai-tay-2,Naive,4,28,87,0
Khoai-tay-2,Naive,5,31,125,0
Khoai-tay-2,Naive,6,62,144,0
Khoai-tay-2,Naive,7,87,141,0
Khoai-tay-2,Naive,8,105,152,0
Khoai-tay-2,Naive,9,75,148,0
Khoai-tay-2,Naive,10,101,149,0
Khoai-tay-2,Naive,11,102,154,0
Khoai-tay-2,Naive,12,95,144,0
Khoai-tay-2,Naive,13,77,149,0
OM-2,Naive,0,1,7,0
OM-2,Naive,1,11,33,0
OM-2,Naive,2,19,62,0
OM-2,Naive,3,29,117,0
OM-2,Naive,4,73,126,0
OM-2,Naive,5,53,135,0
OM-2,Naive,6,73,138,0
OM-2,Naive,7,80,131,0
OM-2,Naive,8,91,141,0
OM-2,Naive,9,90,135,0
OM-2,Naive,10,95,142,0
OM-2,Naive,11,60,133,0
OM-2,Naive,12,58,142,0
Root-beer-1,Electrode-Box-B2,0,11,85,1
Root-beer-1,Electrode-Box-B2,1,18,76,1
Root-beer-1,Electrode-Box-B2,2,40,105,1
Root-beer-1,Electrode-Box-B2,3,55,134,1
Root-beer-1,Electrode-Box-B2,4,75,136,1
Root-beer-1,Electrode-Box-B2,5,64,133,1
Root-beer-1,Electrode-Box-B2,6,104,139,1
Root-beer-1,Electrode-Box-B2,7,98,148,1
Root-beer-1,Electrode-Box-B2,8,81,145,1
Root-beer-1,Electrode-Box-B2,9,89,156,1
Root-beer-1,Electrode-Box-B2,10,105,158,1
Root-beer-2,Electrode-Box-A2,0,22,74,0
Root-beer-2,Electrode-Box-A2,1,31,87,0
Root-beer-2,Electrode-Box-A2,2,49,134,0
Root-beer-2,Electrode-Box-A2,3,31,89,0
Root-beer-2,Electrode-Box-A2,4,60,140,0
Root-beer-2,Electrode-Box-A2,5,84,147,0
Vu-vuong,Naive,0,18,61,0
Vu-vuong,Naive,1,35,91,0
Vu-vuong,Naive,2,61,127,0
Vu-vuong,Naive,3,34,146,0
Vu-vuong,Naive,4,61,141,0
Vu-vuong,Naive,5,37,151,0
Vu-vuong,Naive,6,49,131,0
Vu-vuong,Naive,7,65,149,0
Vu-vuong,Naive,8,67,141,0
Vu-vuong,Naive,9,73,140,0
Vu-vuong,Naive,10,72,131,0
Vu-vuong,Naive,11,89,158,0
Vu-vuong,Naive,12,97,154,0
Vu-vuong,Naive,13,93,145,0
1 subject group day success total stim
2 Banh-mi-1 Electrode-Box-B2 0 13 84 1
3 Banh-mi-1 Electrode-Box-B2 1 35 86 1
4 Banh-mi-1 Electrode-Box-B2 2 47 110 1
5 Banh-mi-1 Electrode-Box-B2 3 65 140 1
6 Banh-mi-1 Electrode-Box-B2 4 70 127 1
7 Banh-mi-1 Electrode-Box-B2 5 102 142 1
8 Banh-mi-1 Electrode-Box-B2 6 90 131 1
9 Banh-mi-1 Electrode-Box-B2 7 109 148 1
10 Banh-mi-1 Electrode-Box-B2 8 104 137 1
11 Banh-mi-1 Electrode-Box-B2 9 119 150 1
12 Banh-mi-1 Electrode-Box-B2 10 121 158 1
13 Banh-mi-1 Electrode-Box-B2 11 121 148 1
14 Banh-mi-1 Electrode-Box-B2 12 120 149 1
15 Banh-mi-1 Electrode-Box-B2 13 135 154 1
16 Banh-mi-2 Electrode-Box-A2 0 25 97 0
17 Banh-mi-2 Electrode-Box-A2 1 22 101 0
18 Banh-mi-2 Electrode-Box-A2 2 22 119 0
19 Banh-mi-2 Electrode-Box-A2 3 29 118 0
20 Banh-mi-2 Electrode-Box-A2 4 27 136 0
21 Banh-mi-2 Electrode-Box-A2 5 43 146 0
22 Banh-mi-2 Electrode-Box-A2 6 74 146 0
23 Banh-mi-2 Electrode-Box-A2 7 70 148 0
24 Banh-mi-2 Electrode-Box-A2 8 65 130 0
25 Banh-mi-2 Electrode-Box-A2 9 79 151 0
26 Banh-mi-2 Electrode-Box-A2 10 93 152 0
27 Egg-tart-1 Electrode-Box-B2 0 7 56 1
28 Egg-tart-1 Electrode-Box-B2 1 16 78 1
29 Egg-tart-1 Electrode-Box-B2 2 23 103 1
30 Egg-tart-1 Electrode-Box-B2 3 63 120 1
31 Egg-tart-1 Electrode-Box-B2 4 69 132 1
32 Egg-tart-1 Electrode-Box-B2 5 83 136 1
33 Egg-tart-1 Electrode-Box-B2 6 71 142 1
34 Egg-tart-1 Electrode-Box-B2 7 79 138 1
35 Egg-tart-1 Electrode-Box-B2 8 98 142 1
36 Egg-tart-1 Electrode-Box-B2 9 89 139 1
37 Egg-tart-1 Electrode-Box-B2 10 96 143 1
38 Egg-tart-1 Electrode-Box-B2 11 96 148 1
39 Egg-tart-1 Electrode-Box-B2 12 101 156 1
40 Egg-tart-1 Electrode-Box-B2 13 103 152 1
41 Egg-tart-2 Electrode-Box-A2 0 9 32 0
42 Egg-tart-2 Electrode-Box-A2 1 2 38 0
43 Egg-tart-2 Electrode-Box-A2 2 31 93 0
44 Egg-tart-2 Electrode-Box-A2 3 44 101 0
45 Egg-tart-2 Electrode-Box-A2 4 54 131 0
46 Egg-tart-2 Electrode-Box-A2 5 84 139 0
47 Egg-tart-2 Electrode-Box-A2 6 85 145 0
48 Egg-tart-2 Electrode-Box-A2 7 79 143 0
49 Egg-tart-2 Electrode-Box-A2 8 76 131 0
50 Egg-tart-2 Electrode-Box-A2 9 88 149 0
51 Egg-tart-2 Electrode-Box-A2 10 81 151 0
52 Egg-tart-2 Electrode-Box-A2 11 78 152 0
53 Egg-tart-2 Electrode-Box-A2 12 96 155 0
54 Egg-tart-2 Electrode-Box-A2 13 84 155 0
55 Khoai-lang-2 Naive 0 0 0 0
56 Khoai-lang-2 Naive 1 0 0 0
57 Khoai-lang-2 Naive 2 10 47 0
58 Khoai-lang-2 Naive 3 11 52 0
59 Khoai-lang-2 Naive 4 9 56 0
60 Khoai-lang-2 Naive 5 34 95 0
61 Khoai-lang-2 Naive 6 21 72 0
62 Khoai-lang-2 Naive 7 23 99 0
63 Khoai-lang-2 Naive 8 64 136 0
64 Khoai-lang-2 Naive 9 75 131 0
65 Khoai-lang-2 Naive 10 63 134 0
66 Khoai-lang-2 Naive 11 59 139 0
67 Khoai-lang-2 Naive 12 51 129 0
68 Khoai-lang-2 Naive 13 73 143 0
69 Khoai-tay-2 Naive 1 21 68 0
70 Khoai-tay-2 Naive 2 6 79 0
71 Khoai-tay-2 Naive 3 0 83 0
72 Khoai-tay-2 Naive 4 28 87 0
73 Khoai-tay-2 Naive 5 31 125 0
74 Khoai-tay-2 Naive 6 62 144 0
75 Khoai-tay-2 Naive 7 87 141 0
76 Khoai-tay-2 Naive 8 105 152 0
77 Khoai-tay-2 Naive 9 75 148 0
78 Khoai-tay-2 Naive 10 101 149 0
79 Khoai-tay-2 Naive 11 102 154 0
80 Khoai-tay-2 Naive 12 95 144 0
81 Khoai-tay-2 Naive 13 77 149 0
82 OM-2 Naive 0 1 7 0
83 OM-2 Naive 1 11 33 0
84 OM-2 Naive 2 19 62 0
85 OM-2 Naive 3 29 117 0
86 OM-2 Naive 4 73 126 0
87 OM-2 Naive 5 53 135 0
88 OM-2 Naive 6 73 138 0
89 OM-2 Naive 7 80 131 0
90 OM-2 Naive 8 91 141 0
91 OM-2 Naive 9 90 135 0
92 OM-2 Naive 10 95 142 0
93 OM-2 Naive 11 60 133 0
94 OM-2 Naive 12 58 142 0
95 Root-beer-1 Electrode-Box-B2 0 11 85 1
96 Root-beer-1 Electrode-Box-B2 1 18 76 1
97 Root-beer-1 Electrode-Box-B2 2 40 105 1
98 Root-beer-1 Electrode-Box-B2 3 55 134 1
99 Root-beer-1 Electrode-Box-B2 4 75 136 1
100 Root-beer-1 Electrode-Box-B2 5 64 133 1
101 Root-beer-1 Electrode-Box-B2 6 104 139 1
102 Root-beer-1 Electrode-Box-B2 7 98 148 1
103 Root-beer-1 Electrode-Box-B2 8 81 145 1
104 Root-beer-1 Electrode-Box-B2 9 89 156 1
105 Root-beer-1 Electrode-Box-B2 10 105 158 1
106 Root-beer-2 Electrode-Box-A2 0 22 74 0
107 Root-beer-2 Electrode-Box-A2 1 31 87 0
108 Root-beer-2 Electrode-Box-A2 2 49 134 0
109 Root-beer-2 Electrode-Box-A2 3 31 89 0
110 Root-beer-2 Electrode-Box-A2 4 60 140 0
111 Root-beer-2 Electrode-Box-A2 5 84 147 0
112 Vu-vuong Naive 0 18 61 0
113 Vu-vuong Naive 1 35 91 0
114 Vu-vuong Naive 2 61 127 0
115 Vu-vuong Naive 3 34 146 0
116 Vu-vuong Naive 4 61 141 0
117 Vu-vuong Naive 5 37 151 0
118 Vu-vuong Naive 6 49 131 0
119 Vu-vuong Naive 7 65 149 0
120 Vu-vuong Naive 8 67 141 0
121 Vu-vuong Naive 9 73 140 0
122 Vu-vuong Naive 10 72 131 0
123 Vu-vuong Naive 11 89 158 0
124 Vu-vuong Naive 12 97 154 0
125 Vu-vuong Naive 13 93 145 0
@@ -0,0 +1,65 @@
==============================================================================
VARIATION: naive_a2_d0_13
==============================================================================
model: behavior ~ stim + day + stim:day + (1|rat) (behavior = success COUNT)
day = training day within window (0 = first analyzed day)
treatment (stim=1): Electrode-Box-B2
control (stim=0): Electrode-Box-A2, Naive
N = 10 rats, 124 sessions raw day coverage: treat 0..13, control 0..13
(equal day coverage over this window)
==============================================================================
FULL MODEL SUMMARY -- fitlme
==============================================================================
Linear mixed-effects model fit by ML
Model information:
Number of observations 124
Fixed effects coefficients 4
Random effects coefficients 10
Covariance parameters 2
Formula:
behavior ~ 1 + day*stim + (1 | rat)
Model fit statistics:
AIC BIC LogLikelihood Deviance
1055.4 1072.3 -521.69 1043.4
Fixed effects coefficients (95% CIs):
Name Estimate SE tStat DF pValue
{'(Intercept)'} 16.252 4.4327 3.6664 120 0.00036779
{'day' } 6.4053 0.43948 14.575 120 2.5469e-28
{'stim' } 11.52 8.023 1.4359 120 0.15363
{'day:stim' } 1.6137 0.77637 2.0785 120 0.039797
Lower Upper
7.4757 25.029
5.5352 7.2755
-4.3648 27.405
0.076509 3.1508
Random effects covariance parameters (95% CIs):
Group: rat (10 Levels)
Name1 Name2 Type Estimate
{'(Intercept)'} {'(Intercept)'} {'std'} 8.4599
Lower Upper
4.8243 14.835
Group: Error
Name Estimate Lower Upper
{'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
interaction 95% CI: [+0.08, +3.15]
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.