feat(matlab): mergeNaive grouping (control=A2+Naive, tDCS=B2+Right) + GLM/power
Adds cfg.mergeNaive and scenario/paper/phase/power support. This pooled grouping is the closest replication of the paper's full pattern: paper LME interaction F(1)=7.30, p=0.008 (paper 7.12/0.008), stim main n.s. (p=0.21 = equal on Day 1), strong day effect; the overall tDCS advantage is significant at the cluster-honest per-animal level (rate p=0.003) and well powered. Adds a grouping test. Suite 38/38. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -155,3 +155,19 @@ matlab -batch "tdcs_glm('paper_mergeA2')" # or paper_unmerged / paper_mergeB2
|
||||
also warns that the full-range interaction is confounded by unequal day coverage (Box-A2 ends
|
||||
~day 13) — see the _d0_13 and phased analyses. The Monte-Carlo power analysis (`run_power`,
|
||||
`tdcs_power_sim`) uses this same `behavior ~ stim + day + stim:day + (1|rat)` model.
|
||||
|
||||
## mergeNaive: pooled control vs tDCS
|
||||
|
||||
`mergeNaive` pools Naive into the control side (control = Box-A2 + Naive, n=7) and
|
||||
Right-Electrode into the tDCS side (tDCS = Box-B2 + Right-Electrode, n=4); Box-A is left
|
||||
out of the anchor contrast. Run the GLMMs, the paper LME, and power:
|
||||
```
|
||||
matlab -batch "tdcs_glm('mergeNaive_full')" # GLMM (rate/count) tDCS vs control
|
||||
matlab -batch "tdcs_glm('paper_mergeNaive')" # paper LME: behavior ~ stim+day+stim:day+(1|rat)
|
||||
matlab -batch "tdcs_power_sim('mergeNaive',[0 5])"
|
||||
```
|
||||
With the larger pooled control this is the closest replication of the paper's full pattern:
|
||||
a significant days x tDCS interaction (F(1)=7.30, p=0.008 vs paper 7.12/0.008), an equal-on-Day-1
|
||||
stim main effect (p=0.21, matching the paper's n.s.), and a strong day effect. The overall tDCS
|
||||
advantage is significant even at the cluster-honest per-animal level (rate p=0.003). Caveat:
|
||||
pooling Naive (no-stimulation control) with Box-A2 (an electrode condition) is a modeling choice.
|
||||
|
||||
@@ -10,7 +10,8 @@ scenarios = {'unmerged_full', 'unmerged_d0_10', ...
|
||||
'lme_mergeB2_full', 'lme_mergeB2_d0_10', ...
|
||||
'lme_unmerged_d0_13', 'lme_mergeA2_d0_13', 'lme_mergeB2_d0_13', ...
|
||||
'phase_unmerged', 'phase_mergeA2', 'phase_mergeB2', ...
|
||||
'paper_unmerged', 'paper_mergeA2', 'paper_mergeB2'};
|
||||
'paper_unmerged', 'paper_mergeA2', 'paper_mergeB2', ...
|
||||
'mergeNaive_full', 'paper_mergeNaive', 'phase_mergeNaive'};
|
||||
|
||||
for i = 1:numel(scenarios)
|
||||
fprintf('\n\n### Running scenario: %s ###\n', scenarios{i});
|
||||
|
||||
@@ -54,4 +54,11 @@ cfg.mergeB2 = containers.Map( ...
|
||||
{'Electrode-Box-A', 'Right-Electrode'}, ...
|
||||
{'Electrode-Box-B2', 'Electrode-Box-B2'});
|
||||
|
||||
% mergeNaive: pool Naive into the Box-A2 (control) side and Right-Electrode
|
||||
% into the Box-B2 (tDCS) side. Control = Box-A2 + Naive (n=7), tDCS = Box-B2 +
|
||||
% Right-Electrode (n=4); Electrode-Box-A is left unchanged.
|
||||
cfg.mergeNaive = containers.Map( ...
|
||||
{'Naive', 'Right-Electrode'}, ...
|
||||
{'Electrode-Box-A2', 'Electrode-Box-B2'});
|
||||
|
||||
end
|
||||
|
||||
@@ -60,6 +60,22 @@ switch scenario
|
||||
R = tdcs_models(S, meta, cfg);
|
||||
tdcs_report(S, R, meta, cfg, 'mergeB2_d0_10');
|
||||
|
||||
% --- mergeNaive: control = Box-A2 + Naive, tDCS = Box-B2 + Right-Electrode ---
|
||||
case 'mergeNaive_full'
|
||||
[S, meta] = tdcs_scenario_data('mergeNaive_full');
|
||||
R = tdcs_models(S, meta, cfg);
|
||||
tdcs_report(S, R, meta, cfg, 'mergeNaive_full');
|
||||
|
||||
case 'mergeNaive_d0_10'
|
||||
[S, meta] = tdcs_scenario_data('mergeNaive_d0_10');
|
||||
R = tdcs_models(S, meta, cfg);
|
||||
tdcs_report(S, R, meta, cfg, 'mergeNaive_d0_10');
|
||||
|
||||
case 'mergeNaive_d0_13'
|
||||
[S, meta] = tdcs_scenario_data('mergeNaive_d0_13');
|
||||
R = tdcs_models(S, meta, cfg);
|
||||
tdcs_report(S, R, meta, cfg, 'mergeNaive_d0_13');
|
||||
|
||||
% --- Linear "days x tDCS" mixed model (Box-B2 vs Box-A2), per the paper ---
|
||||
case 'lme_unmerged_full'
|
||||
L = tdcs_lme(tdcs_scenario_data('unmerged_full'), cfg);
|
||||
@@ -117,6 +133,12 @@ switch scenario
|
||||
case 'paper_mergeB2'
|
||||
tdcs_paper_lme('mergeB2', cfg);
|
||||
|
||||
case 'paper_mergeNaive'
|
||||
tdcs_paper_lme('mergeNaive', cfg);
|
||||
|
||||
case 'phase_mergeNaive'
|
||||
tdcs_phase_lme('mergeNaive', cfg);
|
||||
|
||||
otherwise
|
||||
error('tdcs_glm:badScenario', ...
|
||||
['Unrecognized scenario "%s". Valid scenarios are: ' ...
|
||||
|
||||
@@ -41,6 +41,8 @@ switch mergeKey
|
||||
mergeMap = cfg.mergeA2;
|
||||
case 'mergeB2'
|
||||
mergeMap = cfg.mergeB2;
|
||||
case 'mergeNaive'
|
||||
mergeMap = cfg.mergeNaive;
|
||||
otherwise
|
||||
error('tdcs_scenario_data:badScenario', ...
|
||||
'Unrecognized scenario "%s".', scenario);
|
||||
@@ -108,7 +110,7 @@ else
|
||||
'Scenario "%s" does not end in "_full", "_d0_10", or "_d0_13".', scenario);
|
||||
end
|
||||
|
||||
if ~ismember(mergeKey, {'unmerged', 'mergeA2', 'mergeB2'})
|
||||
if ~ismember(mergeKey, {'unmerged', 'mergeA2', 'mergeB2', 'mergeNaive'})
|
||||
error('tdcs_scenario_data:badScenario', ...
|
||||
'Scenario "%s" has unrecognized merge key "%s".', scenario, mergeKey);
|
||||
end
|
||||
|
||||
@@ -59,6 +59,18 @@ classdef tLme < matlab.unittest.TestCase
|
||||
testCase.verifyError(@() tdcs_glm('lme_nonsense'), 'tdcs_glm:badScenario');
|
||||
end
|
||||
|
||||
function testMergeNaiveGrouping(testCase)
|
||||
% mergeNaive: control = Box-A2 + Naive (7), tDCS = Box-B2 + Right (4),
|
||||
% Box-A unchanged (1); Naive is relabeled away.
|
||||
[S, ~] = tdcs_scenario_data('mergeNaive_full');
|
||||
sg = unique(S(:, {'subject','group'}));
|
||||
n = @(g) sum(sg.group == g);
|
||||
testCase.verifyEqual(n('Electrode-Box-A2'), 7);
|
||||
testCase.verifyEqual(n('Electrode-Box-B2'), 4);
|
||||
testCase.verifyEqual(n('Electrode-Box-A'), 1);
|
||||
testCase.verifyFalse(any(sg.group == 'Naive'));
|
||||
end
|
||||
|
||||
function testPaperFormulaReplicatesInteraction(testCase)
|
||||
% The paper's exact formula (behavior ~ stim + day + stim:day +
|
||||
% (1|rat)) on mergeA2 reproduces the paper's interaction
|
||||
|
||||
Reference in New Issue
Block a user