diff --git a/analysis/matlab/make_variations.m b/analysis/matlab/make_variations.m new file mode 100644 index 0000000..4b425bf --- /dev/null +++ b/analysis/matlab/make_variations.m @@ -0,0 +1,114 @@ +function make_variations() +%MAKE_VARIATIONS Generate one self-contained subfolder per grouping x window. +% MAKE_VARIATIONS() writes analysis/matlab/variations/_/ +% for every combination below, each holding exactly three files: +% data.csv the curated data subset for that variation +% analyze.m a simple, standalone MATLAB script (copy of +% variation_analyze.m) that fits the paper's LME on data.csv +% result.txt the text result that analyze.m produces +% and a top-level variations/SUMMARY.csv indexing all variations. +% +% Groupings (stim = 1 treatment / stim = 0 control; all OTHER groups dropped): +% unmerge Box-B2 vs Box-A2 +% right_only Box-B2 + Right-Elec. vs Box-A2 (Box-A dropped) +% naive_a2 Box-B2 vs Box-A2 + Naive (Right, Box-A dropped) +% naive_boxa Box-B2 vs Box-A2 + Naive + Box-A (Right dropped) +% Windows: 0-10, 0-13, 0-5, 6-10, 6-13. +% +% The model in each analyze.m is the paper's: +% behavior ~ stim + day + stim:day + (1|rat) (behavior = success COUNT). + +thisDir = fileparts(mfilename('fullpath')); +templateScript = fullfile(thisDir, 'variation_analyze.m'); +root = fullfile(thisDir, 'variations'); +if ~exist(root, 'dir'); mkdir(root); end + +B2 = 'Electrode-Box-B2'; A2 = 'Electrode-Box-A2'; NAIVE = 'Naive'; +BOXA = 'Electrode-Box-A'; RIGHT = 'Right-Electrode'; + +% grouping name | treatment groups (stim=1) | control groups (stim=0) +groupings = { + 'unmerge', {B2}, {A2} + 'right_only', {B2, RIGHT}, {A2} + 'naive_a2', {B2}, {A2, NAIVE} + 'naive_boxa', {B2}, {A2, NAIVE, BOXA} + }; + +% window name | [loDay hiDay] +windows = { + 'd0_10', [0 10] + 'd0_13', [0 13] + 'd0_5', [0 5] + 'd6_10', [6 10] + 'd6_13', [6 13] + }; + +T = tdcs_load_data(); +allGroup = cellstr(T.group); + +rows = {}; % accumulate SUMMARY rows +for gi = 1:size(groupings, 1) + gname = groupings{gi, 1}; + treat = groupings{gi, 2}; + ctrl = groupings{gi, 3}; + inTreat = ismember(allGroup, treat); + inCtrl = ismember(allGroup, ctrl); + + for wi = 1:size(windows, 1) + wname = windows{wi, 1}; + w = windows{wi, 2}; + sel = (inTreat | inCtrl) & T.day >= w(1) & T.day <= w(2); + + D = T(sel, :); + stim = double(inTreat(sel)); + Dout = table(string(D.subject), string(D.group), D.day, D.success, ... + D.total, stim, 'VariableNames', ... + {'subject', 'group', 'day', 'success', 'total', 'stim'}); + + vname = [gname '_' wname]; + folder = fullfile(root, vname); + if ~exist(folder, 'dir'); mkdir(folder); end + writetable(Dout, fullfile(folder, 'data.csv')); + copyfile(templateScript, fullfile(folder, 'analyze.m')); + + try + r = localRun(fullfile(folder, 'analyze.m')); + rows(end + 1, :) = {vname, gname, wname, r.nRats, r.nObs, ... + r.covEqual, r.interP, r.interEst, r.stimP, r.dayP}; %#ok + fprintf(' %-16s N=%2d obs=%4d interaction p=%.4g (%+.2f) %s\n', ... + vname, r.nRats, r.nObs, r.interP, r.interEst, ... + localTern(r.covEqual, 'equal-cov', 'UNEQUAL-cov')); + catch ME + localWriteError(folder, ME); + fprintf(2, ' %-16s ERROR: %s\n', vname, ME.message); + end + end +end + +% Top-level index of all variations. +S = cell2table(rows, 'VariableNames', {'variation', 'grouping', 'window', ... + 'nRats', 'nObs', 'covEqual', 'interaction_p', 'interaction_est', ... + 'stim_p', 'day_p'}); +writetable(S, fullfile(root, 'SUMMARY.csv')); +fprintf('\nWrote %d variations under %s\n(index: variations/SUMMARY.csv)\n', ... + size(rows, 1), root); + +end + +function r = localRun(scriptPath) +%LOCALRUN Execute one analyze.m in an isolated workspace and return its +% VARRESULT struct. Isolation prevents the script's variables (D, m, ...) +% from colliding with the generator's loop state. +run(scriptPath); +r = VARRESULT; %#ok (defined by the analyze.m script just run) +end + +function localWriteError(folder, ME) +fid = fopen(fullfile(folder, 'result.txt'), 'w'); +fprintf(fid, 'ERROR fitting this variation:\n%s\n', getReport(ME, 'basic')); +fclose(fid); +end + +function out = localTern(cond, a, b) +if cond; out = a; else; out = b; end +end diff --git a/analysis/matlab/variation_analyze.m b/analysis/matlab/variation_analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variation_analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/SUMMARY.csv b/analysis/matlab/variations/SUMMARY.csv new file mode 100644 index 0000000..d615b84 --- /dev/null +++ b/analysis/matlab/variations/SUMMARY.csv @@ -0,0 +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 diff --git a/analysis/matlab/variations/naive_a2_d0_10/analyze.m b/analysis/matlab/variations/naive_a2_d0_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_a2_d0_10/data.csv b/analysis/matlab/variations/naive_a2_d0_10/data.csv new file mode 100644 index 0000000..f360125 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_10/data.csv @@ -0,0 +1,105 @@ +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-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-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 +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-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 +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 +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 diff --git a/analysis/matlab/variations/naive_a2_d0_10/result.txt b/analysis/matlab/variations/naive_a2_d0_10/result.txt new file mode 100644 index 0000000..2e8e291 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_a2_d0_10 +============================================================================== +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, 104 sessions raw day coverage: treat 0..10, control 0..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 104 + 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 + 869.17 885.04 -428.58 857.17 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 10.33 4.4952 2.298 100 0.023646 + {'day' } 8.0905 0.53615 15.09 100 1.598e-27 + {'stim' } 12.019 8.117 1.4807 100 0.14184 + {'day:stim' } 1.4337 0.92893 1.5434 100 0.12589 + + + Lower Upper + 1.4115 19.248 + 7.0268 9.1542 + -4.0853 28.123 + -0.40926 3.2767 + +Random effects covariance parameters (95% CIs): +Group: rat (10 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 8.753 + + + Lower Upper + 5.0208 15.26 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.41, +3.28] +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. diff --git a/analysis/matlab/variations/naive_a2_d0_13/analyze.m b/analysis/matlab/variations/naive_a2_d0_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_a2_d0_13/data.csv b/analysis/matlab/variations/naive_a2_d0_13/data.csv new file mode 100644 index 0000000..c155957 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_13/data.csv @@ -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 diff --git a/analysis/matlab/variations/naive_a2_d0_13/result.txt b/analysis/matlab/variations/naive_a2_d0_13/result.txt new file mode 100644 index 0000000..cf02d4c --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_13/result.txt @@ -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. diff --git a/analysis/matlab/variations/naive_a2_d0_5/analyze.m b/analysis/matlab/variations/naive_a2_d0_5/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_5/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_a2_d0_5/data.csv b/analysis/matlab/variations/naive_a2_d0_5/data.csv new file mode 100644 index 0000000..81535fc --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_5/data.csv @@ -0,0 +1,60 @@ +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-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 +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-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 +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-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 +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 +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-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 diff --git a/analysis/matlab/variations/naive_a2_d0_5/result.txt b/analysis/matlab/variations/naive_a2_d0_5/result.txt new file mode 100644 index 0000000..c43157d --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d0_5/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_a2_d0_5 +============================================================================== +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, 59 sessions raw day coverage: treat 0..5, control 0..5 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 59 + 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 + 489.28 501.74 -238.64 477.28 + +Fixed effects coefficients (95% CIs): + 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 + {'(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 +interaction 95% CI: [+2.92, +11.00] +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. diff --git a/analysis/matlab/variations/naive_a2_d6_10/analyze.m b/analysis/matlab/variations/naive_a2_d6_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_a2_d6_10/data.csv b/analysis/matlab/variations/naive_a2_d6_10/data.csv new file mode 100644 index 0000000..7643c17 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_10/data.csv @@ -0,0 +1,46 @@ +subject,group,day,success,total,stim +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-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,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-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 +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-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 +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 +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 +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 diff --git a/analysis/matlab/variations/naive_a2_d6_10/result.txt b/analysis/matlab/variations/naive_a2_d6_10/result.txt new file mode 100644 index 0000000..f08be3a --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_a2_d6_10 +============================================================================== +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 = 9 rats, 45 sessions raw day coverage: treat 6..10, control 6..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 45 + Fixed effects coefficients 4 + Random effects coefficients 9 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 368.51 379.35 -178.25 356.51 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 62.1 5.5902 11.109 41 6.1328e-14 + {'day' } 5.9667 1.3623 4.3798 41 8.0273e-05 + {'stim' } 26.433 9.6824 2.73 41 0.0092904 + {'day:stim' } -1.8 2.3596 -0.76285 41 0.44992 + + + Lower Upper + 50.81 73.39 + 3.2154 8.7179 + 6.8793 45.987 + -6.5653 2.9653 + +Random effects covariance parameters (95% CIs): +Group: rat (9 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 10.986 + + + Lower Upper + 6.3454 19.02 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-6.57, +2.97] +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. diff --git a/analysis/matlab/variations/naive_a2_d6_13/analyze.m b/analysis/matlab/variations/naive_a2_d6_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_a2_d6_13/data.csv b/analysis/matlab/variations/naive_a2_d6_13/data.csv new file mode 100644 index 0000000..4a1fcc9 --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_13/data.csv @@ -0,0 +1,66 @@ +subject,group,day,success,total,stim +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,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,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,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,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,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,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,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 +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 diff --git a/analysis/matlab/variations/naive_a2_d6_13/result.txt b/analysis/matlab/variations/naive_a2_d6_13/result.txt new file mode 100644 index 0000000..6b0ff4c --- /dev/null +++ b/analysis/matlab/variations/naive_a2_d6_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_a2_d6_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 = 9 rats, 65 sessions raw day coverage: treat 6..13, control 6..13 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 65 + Fixed effects coefficients 4 + Random effects coefficients 9 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 535.5 548.54 -261.75 523.5 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 66.813 5.1278 13.03 61 2.7998e-19 + {'day' } 2.8262 0.83395 3.3889 61 0.0012345 + {'stim' } 21.913 8.8928 2.4641 61 0.016568 + {'day:stim' } 1.1553 1.4855 0.77769 61 0.43976 + + + Lower Upper + 56.56 77.067 + 1.1586 4.4937 + 4.1309 39.695 + -1.8152 4.1258 + +Random effects covariance parameters (95% CIs): +Group: rat (9 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 9.7589 + + + Lower Upper + 5.6191 16.948 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-1.82, +4.13] +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. diff --git a/analysis/matlab/variations/naive_boxa_d0_10/analyze.m b/analysis/matlab/variations/naive_boxa_d0_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_boxa_d0_10/data.csv b/analysis/matlab/variations/naive_boxa_d0_10/data.csv new file mode 100644 index 0000000..fb15196 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_10/data.csv @@ -0,0 +1,116 @@ +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-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-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 +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-tay-1,Electrode-Box-A,0,14,62,0 +Khoai-tay-1,Electrode-Box-A,1,22,83,0 +Khoai-tay-1,Electrode-Box-A,2,6,79,0 +Khoai-tay-1,Electrode-Box-A,3,28,97,0 +Khoai-tay-1,Electrode-Box-A,4,60,134,0 +Khoai-tay-1,Electrode-Box-A,5,75,138,0 +Khoai-tay-1,Electrode-Box-A,6,81,137,0 +Khoai-tay-1,Electrode-Box-A,7,78,147,0 +Khoai-tay-1,Electrode-Box-A,8,91,132,0 +Khoai-tay-1,Electrode-Box-A,9,99,146,0 +Khoai-tay-1,Electrode-Box-A,10,94,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 +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 +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 diff --git a/analysis/matlab/variations/naive_boxa_d0_10/result.txt b/analysis/matlab/variations/naive_boxa_d0_10/result.txt new file mode 100644 index 0000000..206ef7d --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_boxa_d0_10 +============================================================================== +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-A, Electrode-Box-A2, Naive +N = 11 rats, 115 sessions raw day coverage: treat 0..10, control 0..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 115 + Fixed effects coefficients 4 + Random effects coefficients 11 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 958.48 974.95 -473.24 946.48 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 10.139 4.1642 2.4349 111 0.016488 + {'day' } 8.3463 0.49368 16.906 111 1.7432e-32 + {'stim' } 12.209 7.8948 1.5465 111 0.12484 + {'day:stim' } 1.1779 0.90166 1.3064 111 0.19412 + + + Lower Upper + 1.8878 18.391 + 7.3681 9.3246 + -3.4352 27.853 + -0.60877 2.9646 + +Random effects covariance parameters (95% CIs): +Group: rat (11 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 8.6713 + + + Lower Upper + 5.112 14.709 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.61, +2.96] +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. diff --git a/analysis/matlab/variations/naive_boxa_d0_13/analyze.m b/analysis/matlab/variations/naive_boxa_d0_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_boxa_d0_13/data.csv b/analysis/matlab/variations/naive_boxa_d0_13/data.csv new file mode 100644 index 0000000..2115746 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_13/data.csv @@ -0,0 +1,139 @@ +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-1,Electrode-Box-A,0,14,62,0 +Khoai-tay-1,Electrode-Box-A,1,22,83,0 +Khoai-tay-1,Electrode-Box-A,2,6,79,0 +Khoai-tay-1,Electrode-Box-A,3,28,97,0 +Khoai-tay-1,Electrode-Box-A,4,60,134,0 +Khoai-tay-1,Electrode-Box-A,5,75,138,0 +Khoai-tay-1,Electrode-Box-A,6,81,137,0 +Khoai-tay-1,Electrode-Box-A,7,78,147,0 +Khoai-tay-1,Electrode-Box-A,8,91,132,0 +Khoai-tay-1,Electrode-Box-A,9,99,146,0 +Khoai-tay-1,Electrode-Box-A,10,94,143,0 +Khoai-tay-1,Electrode-Box-A,11,110,156,0 +Khoai-tay-1,Electrode-Box-A,12,105,143,0 +Khoai-tay-1,Electrode-Box-A,13,106,153,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 diff --git a/analysis/matlab/variations/naive_boxa_d0_13/result.txt b/analysis/matlab/variations/naive_boxa_d0_13/result.txt new file mode 100644 index 0000000..65a3e77 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_boxa_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-A, Electrode-Box-A2, Naive +N = 11 rats, 138 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 138 + Fixed effects coefficients 4 + Random effects coefficients 11 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 1172.3 1189.8 -580.14 1160.3 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 15.925 4.1997 3.792 134 0.00022515 + {'day' } 6.7124 0.401 16.739 134 1.2129e-34 + {'stim' } 11.848 7.9908 1.4827 134 0.1405 + {'day:stim' } 1.3064 0.75238 1.7363 134 0.084806 + + + Lower Upper + 7.619 24.231 + 5.9193 7.5055 + -3.9564 27.652 + -0.1817 2.7945 + +Random effects covariance parameters (95% CIs): +Group: rat (11 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 8.76 + + + Lower Upper + 5.1941 14.774 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.18, +2.79] +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. diff --git a/analysis/matlab/variations/naive_boxa_d0_5/analyze.m b/analysis/matlab/variations/naive_boxa_d0_5/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_5/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_boxa_d0_5/data.csv b/analysis/matlab/variations/naive_boxa_d0_5/data.csv new file mode 100644 index 0000000..29319a7 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_5/data.csv @@ -0,0 +1,66 @@ +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-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 +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-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 +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-tay-1,Electrode-Box-A,0,14,62,0 +Khoai-tay-1,Electrode-Box-A,1,22,83,0 +Khoai-tay-1,Electrode-Box-A,2,6,79,0 +Khoai-tay-1,Electrode-Box-A,3,28,97,0 +Khoai-tay-1,Electrode-Box-A,4,60,134,0 +Khoai-tay-1,Electrode-Box-A,5,75,138,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 +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 +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-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 diff --git a/analysis/matlab/variations/naive_boxa_d0_5/result.txt b/analysis/matlab/variations/naive_boxa_d0_5/result.txt new file mode 100644 index 0000000..687f673 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d0_5/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_boxa_d0_5 +============================================================================== +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-A, Electrode-Box-A2, Naive +N = 11 rats, 65 sessions raw day coverage: treat 0..5, control 0..5 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 65 + Fixed effects coefficients 4 + Random effects coefficients 11 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 540.21 553.25 -264.1 528.21 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 8.2006 4.622 1.7743 61 0.081011 + {'day' } 8.8157 1.0827 8.1421 61 2.5062e-11 + {'stim' } 1.3073 8.7275 0.1498 61 0.88142 + {'day:stim' } 6.4033 2.0341 3.1479 61 0.0025447 + + + Lower Upper + -1.0416 17.443 + 6.6507 10.981 + -16.144 18.759 + 2.3358 10.471 + +Random effects covariance parameters (95% CIs): +Group: rat (11 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 9.1032 + + + Lower Upper + 5.2068 15.915 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [+2.34, +10.47] +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. diff --git a/analysis/matlab/variations/naive_boxa_d6_10/analyze.m b/analysis/matlab/variations/naive_boxa_d6_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_boxa_d6_10/data.csv b/analysis/matlab/variations/naive_boxa_d6_10/data.csv new file mode 100644 index 0000000..4941db9 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_10/data.csv @@ -0,0 +1,51 @@ +subject,group,day,success,total,stim +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-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,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-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 +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-tay-1,Electrode-Box-A,6,81,137,0 +Khoai-tay-1,Electrode-Box-A,7,78,147,0 +Khoai-tay-1,Electrode-Box-A,8,91,132,0 +Khoai-tay-1,Electrode-Box-A,9,99,146,0 +Khoai-tay-1,Electrode-Box-A,10,94,143,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 +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 +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 +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 diff --git a/analysis/matlab/variations/naive_boxa_d6_10/result.txt b/analysis/matlab/variations/naive_boxa_d6_10/result.txt new file mode 100644 index 0000000..590e7d3 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_boxa_d6_10 +============================================================================== +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-A, Electrode-Box-A2, Naive +N = 10 rats, 50 sessions raw day coverage: treat 6..10, control 6..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 50 + 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 + 405.22 416.69 -196.61 393.22 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 64.543 5.1823 12.454 46 2.4341e-16 + {'day' } 5.7857 1.2123 4.7727 46 1.8769e-05 + {'stim' } 23.99 9.4616 2.5356 46 0.014689 + {'day:stim' } -1.619 2.2133 -0.73152 46 0.46817 + + + Lower Upper + 54.111 74.974 + 3.3456 8.2259 + 4.9452 43.036 + -6.0741 2.836 + +Random effects covariance parameters (95% CIs): +Group: rat (10 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 11.237 + + + Lower Upper + 6.7417 18.73 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-6.07, +2.84] +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. diff --git a/analysis/matlab/variations/naive_boxa_d6_13/analyze.m b/analysis/matlab/variations/naive_boxa_d6_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/naive_boxa_d6_13/data.csv b/analysis/matlab/variations/naive_boxa_d6_13/data.csv new file mode 100644 index 0000000..de63b69 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_13/data.csv @@ -0,0 +1,74 @@ +subject,group,day,success,total,stim +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,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,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,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,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-1,Electrode-Box-A,6,81,137,0 +Khoai-tay-1,Electrode-Box-A,7,78,147,0 +Khoai-tay-1,Electrode-Box-A,8,91,132,0 +Khoai-tay-1,Electrode-Box-A,9,99,146,0 +Khoai-tay-1,Electrode-Box-A,10,94,143,0 +Khoai-tay-1,Electrode-Box-A,11,110,156,0 +Khoai-tay-1,Electrode-Box-A,12,105,143,0 +Khoai-tay-1,Electrode-Box-A,13,106,153,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,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,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 +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 diff --git a/analysis/matlab/variations/naive_boxa_d6_13/result.txt b/analysis/matlab/variations/naive_boxa_d6_13/result.txt new file mode 100644 index 0000000..ae22789 --- /dev/null +++ b/analysis/matlab/variations/naive_boxa_d6_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: naive_boxa_d6_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-A, Electrode-Box-A2, Naive +N = 10 rats, 73 sessions raw day coverage: treat 6..13, control 6..13 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 73 + 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 + 595.91 609.65 -291.95 583.91 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 68.651 4.9672 13.821 69 1.4737e-21 + {'day' } 3.1029 0.72917 4.2555 69 6.4463e-05 + {'stim' } 20.083 9.0854 2.2105 69 0.030392 + {'day:stim' } 0.87369 1.3869 0.62995 69 0.53081 + + + Lower Upper + 58.741 78.56 + 1.6483 4.5576 + 1.958 38.208 + -1.8931 3.6405 + +Random effects covariance parameters (95% CIs): +Group: rat (10 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 10.755 + + + Lower Upper + 6.51 17.768 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-1.89, +3.64] +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. diff --git a/analysis/matlab/variations/right_only_d0_10/analyze.m b/analysis/matlab/variations/right_only_d0_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/right_only_d0_10/data.csv b/analysis/matlab/variations/right_only_d0_10/data.csv new file mode 100644 index 0000000..5d203fd --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_10/data.csv @@ -0,0 +1,73 @@ +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-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-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 +Khoai-lang-1,Right-Electrode,0,3,69,1 +Khoai-lang-1,Right-Electrode,1,18,97,1 +Khoai-lang-1,Right-Electrode,2,27,84,1 +Khoai-lang-1,Right-Electrode,3,46,121,1 +Khoai-lang-1,Right-Electrode,4,65,143,1 +Khoai-lang-1,Right-Electrode,5,76,141,1 +Khoai-lang-1,Right-Electrode,6,79,146,1 +Khoai-lang-1,Right-Electrode,7,81,153,1 +Khoai-lang-1,Right-Electrode,8,98,144,1 +Khoai-lang-1,Right-Electrode,9,101,149,1 +Khoai-lang-1,Right-Electrode,10,103,150,1 +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 diff --git a/analysis/matlab/variations/right_only_d0_10/result.txt b/analysis/matlab/variations/right_only_d0_10/result.txt new file mode 100644 index 0000000..08784d3 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: right_only_d0_10 +============================================================================== +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, Right-Electrode +control (stim=0): Electrode-Box-A2 +N = 7 rats, 72 sessions raw day coverage: treat 0..10, control 0..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 72 + Fixed effects coefficients 4 + Random effects coefficients 7 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 581.39 595.05 -284.69 569.39 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 17.35 5.0416 3.4414 68 0.00099395 + {'day' } 7.979 0.75658 10.546 68 5.9429e-16 + {'stim' } 2.4226 6.6282 0.36549 68 0.71588 + {'day:stim' } 1.73 0.94724 1.8264 68 0.07218 + + + Lower Upper + 7.2897 27.411 + 6.4693 9.4888 + -10.804 15.649 + -0.16015 3.6202 + +Random effects covariance parameters (95% CIs): +Group: rat (7 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 5.3461 + + + Lower Upper + 2.377 12.024 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.16, +3.62] +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. diff --git a/analysis/matlab/variations/right_only_d0_13/analyze.m b/analysis/matlab/variations/right_only_d0_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/right_only_d0_13/data.csv b/analysis/matlab/variations/right_only_d0_13/data.csv new file mode 100644 index 0000000..14efbf9 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_13/data.csv @@ -0,0 +1,85 @@ +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-1,Right-Electrode,0,3,69,1 +Khoai-lang-1,Right-Electrode,1,18,97,1 +Khoai-lang-1,Right-Electrode,2,27,84,1 +Khoai-lang-1,Right-Electrode,3,46,121,1 +Khoai-lang-1,Right-Electrode,4,65,143,1 +Khoai-lang-1,Right-Electrode,5,76,141,1 +Khoai-lang-1,Right-Electrode,6,79,146,1 +Khoai-lang-1,Right-Electrode,7,81,153,1 +Khoai-lang-1,Right-Electrode,8,98,144,1 +Khoai-lang-1,Right-Electrode,9,101,149,1 +Khoai-lang-1,Right-Electrode,10,103,150,1 +Khoai-lang-1,Right-Electrode,11,113,154,1 +Khoai-lang-1,Right-Electrode,12,117,148,1 +Khoai-lang-1,Right-Electrode,13,114,146,1 +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 diff --git a/analysis/matlab/variations/right_only_d0_13/result.txt b/analysis/matlab/variations/right_only_d0_13/result.txt new file mode 100644 index 0000000..f689e31 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: right_only_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, Right-Electrode +control (stim=0): Electrode-Box-A2 +N = 7 rats, 84 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 84 + Fixed effects coefficients 4 + Random effects coefficients 7 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 695.18 709.77 -341.59 683.18 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 21.7 4.3761 4.9587 80 3.9065e-06 + {'day' } 6.4863 0.68669 9.4459 80 1.1708e-14 + {'stim' } 3.5986 5.6847 0.63303 80 0.52852 + {'day:stim' } 1.7002 0.84679 2.0078 80 0.048042 + + + Lower Upper + 12.991 30.409 + 5.1198 7.8529 + -7.7143 14.911 + 0.015009 3.3853 + +Random effects covariance parameters (95% CIs): +Group: rat (7 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 3.1353e-15 + + + Lower Upper + NaN NaN + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [+0.02, +3.39] +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. diff --git a/analysis/matlab/variations/right_only_d0_5/analyze.m b/analysis/matlab/variations/right_only_d0_5/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_5/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/right_only_d0_5/data.csv b/analysis/matlab/variations/right_only_d0_5/data.csv new file mode 100644 index 0000000..8f28b35 --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_5/data.csv @@ -0,0 +1,43 @@ +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-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 +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-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 +Khoai-lang-1,Right-Electrode,0,3,69,1 +Khoai-lang-1,Right-Electrode,1,18,97,1 +Khoai-lang-1,Right-Electrode,2,27,84,1 +Khoai-lang-1,Right-Electrode,3,46,121,1 +Khoai-lang-1,Right-Electrode,4,65,143,1 +Khoai-lang-1,Right-Electrode,5,76,141,1 +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-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 diff --git a/analysis/matlab/variations/right_only_d0_5/result.txt b/analysis/matlab/variations/right_only_d0_5/result.txt new file mode 100644 index 0000000..44e70ce --- /dev/null +++ b/analysis/matlab/variations/right_only_d0_5/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: right_only_d0_5 +============================================================================== +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, Right-Electrode +control (stim=0): Electrode-Box-A2 +N = 7 rats, 42 sessions raw day coverage: treat 0..5, control 0..5 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 42 + Fixed effects coefficients 4 + Random effects coefficients 7 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 331.16 341.59 -159.58 319.16 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 12.524 5.1493 2.4321 38 0.019831 + {'day' } 9.8571 1.3751 7.1681 38 1.4583e-08 + {'stim' } -4.9762 6.8119 -0.73051 38 0.46956 + {'day:stim' } 5.3071 1.8191 2.9174 38 0.0058973 + + + Lower Upper + 2.0996 22.948 + 7.0733 12.641 + -18.766 8.8138 + 1.6245 8.9898 + +Random effects covariance parameters (95% CIs): +Group: rat (7 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 5.2482 + + + Lower Upper + 2.2427 12.282 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [+1.62, +8.99] +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. diff --git a/analysis/matlab/variations/right_only_d6_10/analyze.m b/analysis/matlab/variations/right_only_d6_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/right_only_d6_10/data.csv b/analysis/matlab/variations/right_only_d6_10/data.csv new file mode 100644 index 0000000..ddc89a2 --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_10/data.csv @@ -0,0 +1,31 @@ +subject,group,day,success,total,stim +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-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,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-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 +Khoai-lang-1,Right-Electrode,6,79,146,1 +Khoai-lang-1,Right-Electrode,7,81,153,1 +Khoai-lang-1,Right-Electrode,8,98,144,1 +Khoai-lang-1,Right-Electrode,9,101,149,1 +Khoai-lang-1,Right-Electrode,10,103,150,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 diff --git a/analysis/matlab/variations/right_only_d6_10/result.txt b/analysis/matlab/variations/right_only_d6_10/result.txt new file mode 100644 index 0000000..a159886 --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: right_only_d6_10 +============================================================================== +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, Right-Electrode +control (stim=0): Electrode-Box-A2 +N = 6 rats, 30 sessions raw day coverage: treat 6..10, control 6..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 30 + Fixed effects coefficients 4 + Random effects coefficients 6 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 230.64 239.05 -109.32 218.64 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 74.2 6.0309 12.303 26 2.4061e-12 + {'day' } 2.4 1.8291 1.3121 26 0.20096 + {'stim' } 11.9 7.3864 1.6111 26 0.11924 + {'day:stim' } 2.425 2.2402 1.0825 26 0.28898 + + + Lower Upper + 61.803 86.597 + -1.3599 6.1599 + -3.2829 27.083 + -2.1799 7.0299 + +Random effects covariance parameters (95% CIs): +Group: rat (6 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 5.7092 + + + Lower Upper + 2.5487 12.789 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-2.18, +7.03] +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. diff --git a/analysis/matlab/variations/right_only_d6_13/analyze.m b/analysis/matlab/variations/right_only_d6_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/right_only_d6_13/data.csv b/analysis/matlab/variations/right_only_d6_13/data.csv new file mode 100644 index 0000000..971cbee --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_13/data.csv @@ -0,0 +1,43 @@ +subject,group,day,success,total,stim +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,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,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,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-1,Right-Electrode,6,79,146,1 +Khoai-lang-1,Right-Electrode,7,81,153,1 +Khoai-lang-1,Right-Electrode,8,98,144,1 +Khoai-lang-1,Right-Electrode,9,101,149,1 +Khoai-lang-1,Right-Electrode,10,103,150,1 +Khoai-lang-1,Right-Electrode,11,113,154,1 +Khoai-lang-1,Right-Electrode,12,117,148,1 +Khoai-lang-1,Right-Electrode,13,114,146,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 diff --git a/analysis/matlab/variations/right_only_d6_13/result.txt b/analysis/matlab/variations/right_only_d6_13/result.txt new file mode 100644 index 0000000..ce70ce3 --- /dev/null +++ b/analysis/matlab/variations/right_only_d6_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: right_only_d6_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, Right-Electrode +control (stim=0): Electrode-Box-A2 +N = 6 rats, 42 sessions raw day coverage: treat 6..13, control 6..13 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 42 + Fixed effects coefficients 4 + Random effects coefficients 6 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 309.98 320.4 -148.99 297.98 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 75.163 5.7598 13.049 38 1.2935e-15 + {'day' } 1.7153 1.01 1.6984 38 0.097608 + {'stim' } 11.525 7.0338 1.6386 38 0.10956 + {'day:stim' } 2.7579 1.1891 2.3193 38 0.02585 + + + Lower Upper + 63.503 86.823 + -0.32925 3.7599 + -2.7138 25.764 + 0.35071 5.1651 + +Random effects covariance parameters (95% CIs): +Group: rat (6 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 6.4688 + + + Lower Upper + 3.3423 12.52 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [+0.35, +5.17] +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. diff --git a/analysis/matlab/variations/unmerge_d0_10/analyze.m b/analysis/matlab/variations/unmerge_d0_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/unmerge_d0_10/data.csv b/analysis/matlab/variations/unmerge_d0_10/data.csv new file mode 100644 index 0000000..3485c1b --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_10/data.csv @@ -0,0 +1,62 @@ +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-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-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 +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 diff --git a/analysis/matlab/variations/unmerge_d0_10/result.txt b/analysis/matlab/variations/unmerge_d0_10/result.txt new file mode 100644 index 0000000..408e850 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: unmerge_d0_10 +============================================================================== +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 +N = 6 rats, 61 sessions raw day coverage: treat 0..10, control 0..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 61 + Fixed effects coefficients 4 + Random effects coefficients 6 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 499.59 512.25 -243.79 487.59 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 17.372 5.1906 3.3469 57 0.0014518 + {'day' } 7.9666 0.79053 10.077 57 2.8317e-14 + {'stim' } 4.9763 7.2862 0.68298 57 0.49739 + {'day:stim' } 1.5577 1.0483 1.4858 57 0.14283 + + + Lower Upper + 6.9783 27.766 + 6.3836 9.5496 + -9.614 19.567 + -0.5416 3.6569 + +Random effects covariance parameters (95% CIs): +Group: rat (6 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 5.3536 + + + Lower Upper + 2.1542 13.305 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.54, +3.66] +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. diff --git a/analysis/matlab/variations/unmerge_d0_13/analyze.m b/analysis/matlab/variations/unmerge_d0_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/unmerge_d0_13/data.csv b/analysis/matlab/variations/unmerge_d0_13/data.csv new file mode 100644 index 0000000..a36f9a0 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_13/data.csv @@ -0,0 +1,71 @@ +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 +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 diff --git a/analysis/matlab/variations/unmerge_d0_13/result.txt b/analysis/matlab/variations/unmerge_d0_13/result.txt new file mode 100644 index 0000000..18d3c1c --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: unmerge_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 +N = 6 rats, 70 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 70 + Fixed effects coefficients 4 + Random effects coefficients 6 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 586.72 600.22 -287.36 574.72 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 21.7 4.5484 4.7709 66 1.0537e-05 + {'day' } 6.4863 0.71372 9.0881 66 3.0346e-13 + {'stim' } 6.0226 6.3135 0.95392 66 0.3436 + {'day:stim' } 1.5467 0.93755 1.6497 66 0.10376 + + + Lower Upper + 12.619 30.781 + 5.0614 7.9113 + -6.5827 18.628 + -0.32523 3.4185 + +Random effects covariance parameters (95% CIs): +Group: rat (6 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 0 + + + Lower Upper + NaN NaN + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.33, +3.42] +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. diff --git a/analysis/matlab/variations/unmerge_d0_5/analyze.m b/analysis/matlab/variations/unmerge_d0_5/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_5/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/unmerge_d0_5/data.csv b/analysis/matlab/variations/unmerge_d0_5/data.csv new file mode 100644 index 0000000..771d8cf --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_5/data.csv @@ -0,0 +1,37 @@ +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-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 +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-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 +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-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 diff --git a/analysis/matlab/variations/unmerge_d0_5/result.txt b/analysis/matlab/variations/unmerge_d0_5/result.txt new file mode 100644 index 0000000..c7586c8 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d0_5/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: unmerge_d0_5 +============================================================================== +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 +N = 6 rats, 36 sessions raw day coverage: treat 0..5, control 0..5 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 36 + Fixed effects coefficients 4 + Random effects coefficients 6 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 289.66 299.16 -138.83 277.66 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 12.524 5.2775 2.3731 32 0.023816 + {'day' } 9.8571 1.4772 6.6729 32 1.5706e-07 + {'stim' } -3.0159 7.4635 -0.40408 32 0.68884 + {'day:stim' } 5.3619 2.089 2.5667 32 0.015149 + + + Lower Upper + 1.7739 23.274 + 6.8482 12.866 + -18.219 12.187 + 1.1067 9.6172 + +Random effects covariance parameters (95% CIs): +Group: rat (6 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 4.8527 + + + Lower Upper + 1.7069 13.796 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [+1.11, +9.62] +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. diff --git a/analysis/matlab/variations/unmerge_d6_10/analyze.m b/analysis/matlab/variations/unmerge_d6_10/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_10/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/unmerge_d6_10/data.csv b/analysis/matlab/variations/unmerge_d6_10/data.csv new file mode 100644 index 0000000..c47a16b --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_10/data.csv @@ -0,0 +1,26 @@ +subject,group,day,success,total,stim +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-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,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-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 +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 diff --git a/analysis/matlab/variations/unmerge_d6_10/result.txt b/analysis/matlab/variations/unmerge_d6_10/result.txt new file mode 100644 index 0000000..f019624 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_10/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: unmerge_d6_10 +============================================================================== +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 +N = 5 rats, 25 sessions raw day coverage: treat 6..10, control 6..10 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 25 + Fixed effects coefficients 4 + Random effects coefficients 5 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 196.97 204.29 -92.486 184.97 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 74.2 6.4017 11.591 21 1.3774e-10 + {'day' } 2.4 1.9295 1.2439 21 0.22726 + {'stim' } 14.333 8.2646 1.7343 21 0.097522 + {'day:stim' } 1.7667 2.491 0.70923 21 0.48598 + + + Lower Upper + 60.887 87.513 + -1.6126 6.4126 + -2.8539 31.521 + -3.4136 6.9469 + +Random effects covariance parameters (95% CIs): +Group: rat (5 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 6.1065 + + + Lower Upper + 2.5428 14.665 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-3.41, +6.95] +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. diff --git a/analysis/matlab/variations/unmerge_d6_13/analyze.m b/analysis/matlab/variations/unmerge_d6_13/analyze.m new file mode 100644 index 0000000..5fcbc92 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_13/analyze.m @@ -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)'), '', ''); +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); diff --git a/analysis/matlab/variations/unmerge_d6_13/data.csv b/analysis/matlab/variations/unmerge_d6_13/data.csv new file mode 100644 index 0000000..6ea09ce --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_13/data.csv @@ -0,0 +1,35 @@ +subject,group,day,success,total,stim +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,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,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,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 +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 diff --git a/analysis/matlab/variations/unmerge_d6_13/result.txt b/analysis/matlab/variations/unmerge_d6_13/result.txt new file mode 100644 index 0000000..47ffce7 --- /dev/null +++ b/analysis/matlab/variations/unmerge_d6_13/result.txt @@ -0,0 +1,65 @@ +============================================================================== +VARIATION: unmerge_d6_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 +N = 5 rats, 34 sessions raw day coverage: treat 6..13, control 6..13 +(equal day coverage over this window) + +============================================================================== +FULL MODEL SUMMARY -- fitlme +============================================================================== + +Linear mixed-effects model fit by ML + +Model information: + Number of observations 34 + Fixed effects coefficients 4 + Random effects coefficients 5 + Covariance parameters 2 + +Formula: + behavior ~ 1 + day*stim + (1 | rat) + +Model fit statistics: + AIC BIC LogLikelihood Deviance + 257.04 266.2 -122.52 245.04 + +Fixed effects coefficients (95% CIs): + Name Estimate SE tStat DF pValue + {'(Intercept)'} 75.17 6.2311 12.064 30 4.8879e-13 + {'day' } 1.7101 1.061 1.6117 30 0.11749 + {'stim' } 13.563 8.0252 1.69 30 0.1014 + {'day:stim' } 2.267 1.3237 1.7126 30 0.097101 + + + Lower Upper + 62.445 87.896 + -0.45682 3.877 + -2.8271 29.952 + -0.43635 4.9703 + +Random effects covariance parameters (95% CIs): +Group: rat (5 Levels) + Name1 Name2 Type Estimate + {'(Intercept)'} {'(Intercept)'} {'std'} 7.1166 + + + Lower Upper + 3.4834 14.539 + +Group: Error + Name Estimate Lower Upper + {'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 +interaction 95% CI: [-0.44, +4.97] +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.