Pairwise post-hoc testing using coefTest

29 visualizaciones (últimos 30 días)
James Akula
James Akula el 21 de Abr. de 2022
Comentada: MM el 9 de Sept. de 2023
Hello,
I found this post from back in 2015 but it doesn't seem to answer the question (and if it does, I am sorry that I am missing it!). I am trying to understand how I can test for differences within a level of an interaction. For this purpose I have created a random dataset with known properties. In my mock dataset, I have a group of subjects who participate in something-or-other. They can belong to one of three Groups (ABC) at the time of test. Then, we have three factors (ABC) under which we have three levels for each (A-DEF, B-GHI, C-JKL). I arranged the data such that of the groupings, only Group C has any effect (i.e., 2) and then there is a significant interaction factor C, in that if you have level L, you get a big boost.
Thus, any analysis should hopefully detect a signficiant main effect of Group and a significant Group x Factor C interaction effect, but no other obvious effects. Within the effect of Group, it should be level C that stands out. Within the interaction, it should be level L that stands out.
My mock dataset is attached.
To test my understanding, I generated the below script. In it, I am (very sure) I am correctly using coefTest to detect the significant main and interaction effects. Within the main effect, I am (somewhat sure) I am correctly using coefTest to perform pairwise comparisons among Groups ABC; as predicted, I find that C is different from both A and B, while A and B do not differ.
However, within the interaction effect, I would like to test for differences among levels JKL. Can this be done? If so, can someone please help me to do so?
Thank you!!!
load table.mat
mdl = fitlme(d, ...
'Value ~ Group*FactorA + Group*FactorB + Group*FactorC + (1|Subject)', ...
'DummyVarCoding', 'effects', 'FitMethod', 'REML');
disp(mdl)
%% Generate predictions for ALL data
g = unique(d.Group);
a = unique(d.FactorA);
b = unique(d.FactorB);
c = unique(d.FactorC);
cv = sortrows(combvec(1:numel(g), 1:numel(a), 1:numel(b), 1:numel(c))');
predTable = table();
predTable.Subject(1:size(cv, 1),1) = categorical({'Generic'});
predTable.Group = g(cv(:,1),1);
predTable.FactorA = a(cv(:,2),1);
predTable.FactorB = b(cv(:,3),1);
predTable.FactorC = c(cv(:,4),1);
predTable.Value = predict(mdl, predTable, 'Conditional', false);
% Trim to only Groups and then only groupxfactor C interaction
[~, ia, ~] = unique(predTable.Group);
groupTable = removevars(predTable(ia,:), ...
{'Subject', 'FactorA', 'FactorB', 'FactorC'});
groupTable.Value = splitapply(@mean, predTable.Value, ...
findgroups(predTable.Group));
[~, ia, ~] = unique(predTable.FactorC);
AxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
AxFactorCTable.Value = splitapply(@mean, ...
predTable.Value(predTable.Group == 'A'), ...
findgroups(predTable.FactorC(predTable.Group == 'A')));
BxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
BxFactorCTable.Value = splitapply(@mean, ...
predTable.Value(predTable.Group == 'B'), ...
findgroups(predTable.FactorC(predTable.Group == 'B')));
CxFactorCTable = removevars(predTable(ia,:), ...
{'Subject', 'Group', 'FactorA', 'FactorB'});
CxFactorCTable.Value = splitapply(@mean, ...
predTable.Value(predTable.Group == 'C'), ...
findgroups(predTable.FactorC(predTable.Group == 'C')));
figure('units', 'normalized', 'outerposition', [0; 0; 1; 1])
subplot(2, 3, 2)
bar(groupTable.Group, groupTable. Value)
title('Group Means')
ylim([-3, 6])
axis square
subplot(2, 3, 4)
bar(AxFactorCTable.FactorC, AxFactorCTable. Value)
title('Factor C Means for Group A')
ylim([-3, 6])
axis square
subplot(2, 3, 5)
bar(BxFactorCTable.FactorC, BxFactorCTable. Value)
title('Factor C Means for Group B')
ylim([-3, 6])
axis square
subplot(2, 3, 6)
bar(CxFactorCTable.FactorC, CxFactorCTable. Value)
title('Factor C Means for Group C')
ylim([-3, 6])
axis square
% Perform pairwise testing among the main effects for each group.
% Because Group C is not assigned to an effect, it can be tricky to do
% pairwise comparisons with it. However, following the comparison
% approach found at
% https://www.mathworks.com/help/stats/generalizedlinearmixedmodel.coeftest.html,
% we can determine what the post hoc arrangements should be:
% syms A B C
% f1 = A + B + C == 0;
% C = solve(f1, C)
% fAB = A - B
% fAC = A - C
% fBC = B - C
% The results are:
% C = -A - B
% fAB = A - B
% fAC = 2*A + B
% fBC = A + 2*B
% Thus:
% [Int, G_A, G_B, FA_D, FA_E, FB_G, FB_H, FC_J, FC_K, G_A:FA_D, G_B:FA_D, G_A:FA_E, G_B:FA_E, G_A:FB_G, G_B:FB_G, G_A:FB_H, G_B:FB_H, G_A:FC_J, G_B:FC_J, G_A:FC_K, G_B:FC_K]
HAB = [ 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
HAC = [ 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
HBC = [ 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pG = coefTest(mdl, [HAB; HAC; HBC]);
pAB = coefTest(mdl, HAB);
pAC = coefTest(mdl, HAC);
pBC = coefTest(mdl, HBC);
disp(['Significance of Group effect: ', num2str(pG, 3)])
disp([' * Significance of Group A vs. Group B difference: ', ...
num2str(pAB, 3)])
disp([' * Significance of Group A vs. Group C difference: ', ...
num2str(pAC, 3)])
disp([' * Significance of Group B vs. Group C difference: ', ...
num2str(pBC, 3)])
% Test for significant Group x Factor interactions:
% [Int, G_A, G_B, FA_D, FA_E, FB_G, FB_H, FC_J, FC_K, G_A:FA_D, G_B:FA_D, G_A:FA_E, G_B:FA_E, G_A:FB_G, G_B:FB_G, G_A:FB_H, G_B:FB_H, G_A:FC_J, G_B:FC_J, G_A:FC_K, G_B:FC_K]
HG_FA = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]];
HG_FB = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]];
HG_FC = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]; ...
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]];
pG_FA = coefTest(mdl, HG_FA);
pG_FB = coefTest(mdl, HG_FB);
pG_FC = coefTest(mdl, HG_FC);
disp(' ')
disp(['Significance of Group vs. Factor A interaction: ', ...
num2str(pG_FA, 3)]);
disp(['Significance of Group vs. Factor B interaction: ', ...
num2str(pG_FB, 3)]);
disp(['Significance of Group vs. Factor C interaction: ', ...
num2str(pG_FC, 3)]);
disp(' * Here''s where I would like to test for differences among JKL within Group C')
% Uncomment to check above against MATLAB anova
% disp(' ')
% disp(anova(mdl))
  4 comentarios
Scott MacKenzie
Scott MacKenzie el 24 de Abr. de 2022
Sorry, but I don't think I can be of any help here. I don't have experience doing pairwise comparisons in the manner you are describing. But, good luck.
James Akula
James Akula el 25 de Abr. de 2022
Thanks. I do beleive I solved it.

Iniciar sesión para comentar.

Respuesta aceptada

James Akula
James Akula el 25 de Abr. de 2022
I do believe I answered the question. Adding the following code to the problem seems to give me the answer I want. Uncommenting the symbolic bits leads to the answer.
% To do a pairwise comparison deep in the interaction effect gets tricky.
% Here, we need to figure out what the comparisons should be for a nested
% interaction effect. However, we can solve for the needed factors using
% the same approach as above:
% syms Group_A_FactorC_J Group_B_FactorC_J Group_C_FactorC_J ...
% Group_A_FactorC_K Group_B_FactorC_K Group_C_FactorC_K ...
% Group_A_FactorC_L Group_B_FactorC_L Group_C_FactorC_L
%
% Group_C_FactorC_J = -Group_A_FactorC_J - Group_B_FactorC_J;
% Group_C_FactorC_K = -Group_A_FactorC_K - Group_B_FactorC_K;
% Group_C_FactorC_L = -Group_C_FactorC_J - Group_C_FactorC_K;
%
% fGC_FC_JK = Group_C_FactorC_J - Group_C_FactorC_K
% fGC_FC_JL = Group_C_FactorC_J - Group_C_FactorC_L
% fGC_FC_KL = Group_C_FactorC_K - Group_C_FactorC_L
% The answers are:
% fGC_FC_JK = -Group_A_FactorC_J - Group_B_FactorC_J + Group_A_FactorC_K + Group_B_FactorC_K
% fGC_FC_JL = -2*Group_A_FactorC_J - 2*Group_B_FactorC_J - Group_A_FactorC_K - Group_B_FactorC_K
% fGC_FC_KL = -Group_A_FactorC_J - Group_B_FactorC_J - 2*Group_A_FactorC_K - 2*Group_B_FactorC_K
% Thus
% [Int, G_A, G_B, FA_D, FA_E, FB_G, FB_H, FC_J, FC_K, G_A:FA_D, G_B:FA_D, G_A:FA_E, G_B:FA_E, G_A:FB_G, G_B:FB_G, G_A:FB_H, G_B:FB_H, G_A:FC_J, G_B:FC_J, G_A:FC_K, G_B:FC_K]
HGC_FC_JK = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 1, 1];
HGC_FC_JL = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -1, -1];
HGC_FC_KL = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -2, -2];
pGC_FC_JK = coefTest(mdl, HGC_FC_JK);
pGC_FC_JL = coefTest(mdl, HGC_FC_JL);
pGC_FC_KL = coefTest(mdl, HGC_FC_KL);
disp([' * Significance of Factor C-J vs. Factor C-K difference within Group C: ', ...
num2str(pGC_FC_JK, 3)])
disp([' * Significance of Factor C-J vs. Factor C-L difference within Group C: ', ...
num2str(pGC_FC_JL, 3)])
disp([' * Significance of Factor C-K vs. Factor C-L difference within Group C: ', ...
num2str(pGC_FC_KL, 3)])
  1 comentario
MM
MM el 9 de Sept. de 2023
Hi James,
I thought your approach could work for my problem.
I have 3 factors with each having multiple levels. Factor color has 3 levels, order has 4 levels and condition has 5 levels. I want to look at the main and interaction effect on the outcome variable, individual_correction_error. I have subjects as the random effect.
I have excluded condition_3 as there was no data there.
I would like to use coeftest to do post hoc analysis on the interaction effects (condn*order). How do I go about building the contrast matrix for sepcifically testing the interaction between condition and order?
This is the output of fitlme on the model ('individual_correction_error ~ color*condition*order+(1|subject)')
lm_full_condition =
Linear mixed-effects model fit by ML
Model information:
Number of observations 2286
Fixed effects coefficients 48
Random effects coefficients 45
Covariance parameters 2
Formula:
individual_correction_error ~ 1 + color*condition + color*order + condition*order + color:condition:order + (1 | subject)
Model fit statistics:
AIC BIC LogLikelihood Deviance
12030 12316 -5964.9 11930
Fixed effects coefficients (95% CIs):
Name Estimate SE tStat DF pValue Lower Upper
{'(Intercept)' } -0.15933 0.74743 -0.21317 2238 0.83121 -1.6251 1.3064
{'color_blue' } -0.1484 0.098592 -1.5052 2238 0.13241 -0.34174 0.044939
{'color_green' } 0.13717 0.098592 1.3912 2238 0.16429 -0.056176 0.33051
{'condition_4' } -2.8125 0.15171 -18.538 2238 1.7385e-71 -3.11 -2.515
{'condition_2' } -0.13007 0.11213 -1.16 2238 0.24619 -0.34996 0.089826
{'condition_1' } 3.0123 0.16372 18.398 2238 1.6508e-70 2.6912 3.3333
{'order_[0 1 2 4 3]' } 1.1165 0.8071 1.3834 2238 0.16669 -0.46624 2.6993
{'order_[0 2 3 1 4]' } 0.14848 1.3039 0.11387 2238 0.90935 -2.4085 2.7055
{'order_[0 3 4 2 1]' } -2.3417 1.2672 -1.8478 2238 0.064757 -4.8267 0.14343
{'color_blue:condition_4' } 0.27389 0.18359 1.4918 2238 0.13588 -0.086139 0.63392
{'color_green:condition_4' } -0.34359 0.18359 -1.8715 2238 0.061407 -0.70362 0.016437
{'color_blue:condition_2' } -0.12677 0.15211 -0.83338 2238 0.40472 -0.42507 0.17153
{'color_green:condition_2' } 0.075611 0.15211 0.49707 2238 0.61919 -0.22269 0.37391
{'color_blue:condition_1' } -0.25319 0.19023 -1.331 2238 0.18332 -0.62623 0.11985
{'color_green:condition_1' } 0.14719 0.19023 0.77377 2238 0.43915 -0.22585 0.52023
{'color_blue:order_[0 1 2 4 3]' } 0.30762 0.17161 1.7925 2238 0.073182 -0.028914 0.64416
{'color_green:order_[0 1 2 4 3]' } -0.30302 0.17161 -1.7657 2238 0.077581 -0.63956 0.033519
{'color_blue:order_[0 2 3 1 4]' } 0.10408 0.17381 0.59878 2238 0.54938 -0.23677 0.44492
{'color_green:order_[0 2 3 1 4]' } -0.013282 0.17381 -0.076417 2238 0.93909 -0.35413 0.32757
{'color_blue:order_[0 3 4 2 1]' } -0.33717 0.1713 -1.9682 2238 0.049165 -0.6731 -0.0012345
{'color_green:order_[0 3 4 2 1]' } 0.26726 0.1713 1.5601 2238 0.11887 -0.068678 0.60319
{'condition_4:order_[0 1 2 4 3]' } 0.11191 0.2537 0.44112 2238 0.65917 -0.3856 0.60943
{'condition_2:order_[0 1 2 4 3]' } 0.64807 0.20125 3.2203 2238 0.001299 0.25342 1.0427
{'condition_1:order_[0 1 2 4 3]' } -0.38955 0.2858 -1.363 2238 0.17301 -0.95002 0.17091
{'condition_4:order_[0 2 3 1 4]' } 0.78129 0.29921 2.6112 2238 0.0090828 0.19454 1.368
{'condition_2:order_[0 2 3 1 4]' } -0.72327 0.1926 -3.7553 2238 0.00017757 -1.101 -0.34557
{'condition_1:order_[0 2 3 1 4]' } -0.50564 0.25323 -1.9968 2238 0.045969 -1.0022 -0.0090558
{'condition_4:order_[0 3 4 2 1]' } -1.2315 0.24498 -5.0268 2238 5.3815e-07 -1.7119 -0.75105
{'condition_2:order_[0 3 4 2 1]' } -1.1713 0.19561 -5.988 2238 2.4683e-09 -1.5549 -0.78773
{'condition_1:order_[0 3 4 2 1]' } 2.3455 0.29693 7.8989 2238 4.3708e-15 1.7632 2.9278
{'color_blue:condition_4:order_[0 1 2 4 3]' } 0.12839 0.3146 0.4081 2238 0.68324 -0.48854 0.74532
{'color_green:condition_4:order_[0 1 2 4 3]'} 0.14677 0.3146 0.46654 2238 0.64088 -0.47016 0.7637
{'color_blue:condition_2:order_[0 1 2 4 3]' } -0.10329 0.2706 -0.3817 2238 0.70272 -0.63394 0.42737
{'color_green:condition_2:order_[0 1 2 4 3]'} 0.14738 0.2706 0.54464 2238 0.58606 -0.38328 0.67804
{'color_blue:condition_1:order_[0 1 2 4 3]' } 0.17675 0.3325 0.53158 2238 0.59507 -0.47529 0.82879
{'color_green:condition_1:order_[0 1 2 4 3]'} -0.22094 0.3325 -0.66448 2238 0.50645 -0.87298 0.4311
{'color_blue:condition_4:order_[0 2 3 1 4]' } -0.033804 0.34999 -0.096585 2238 0.92306 -0.72015 0.65254
{'color_green:condition_4:order_[0 2 3 1 4]'} -0.20315 0.34999 -0.58045 2238 0.56167 -0.8895 0.48319
{'color_blue:condition_2:order_[0 2 3 1 4]' } 0.2268 0.26636 0.85149 2238 0.39459 -0.29554 0.74914
{'color_green:condition_2:order_[0 2 3 1 4]'} -0.13989 0.26636 -0.52518 2238 0.59951 -0.66223 0.38245
{'color_blue:condition_1:order_[0 2 3 1 4]' } 0.30113 0.30137 0.9992 2238 0.3178 -0.28987 0.89213
{'color_green:condition_1:order_[0 2 3 1 4]'} -0.089843 0.30137 -0.29811 2238 0.76565 -0.68084 0.50116
{'color_blue:condition_4:order_[0 3 4 2 1]' } 0.36974 0.30391 1.2166 2238 0.22388 -0.22623 0.96571
{'color_green:condition_4:order_[0 3 4 2 1]'} -0.021389 0.30391 -0.07038 2238 0.9439 -0.61736 0.57458
{'color_blue:condition_2:order_[0 3 4 2 1]' } -0.13751 0.26 -0.52888 2238 0.59694 -0.64738 0.37236
{'color_green:condition_2:order_[0 3 4 2 1]'} -0.11538 0.26 -0.44375 2238 0.65726 -0.62524 0.39449
{'color_blue:condition_1:order_[0 3 4 2 1]' } -0.73679 0.35229 -2.0914 2238 0.036604 -1.4276 -0.045935
{'color_green:condition_1:order_[0 3 4 2 1]'} 0.48379 0.35229 1.3732 2238 0.16981 -0.20707 1.1746
Random effects covariance parameters (95% CIs):
Group: subject (45 Levels)
Name1 Name2 Type Estimate Lower Upper
{'(Intercept)'} {'(Intercept)'} {'std'} 4.9857 4.0418 6.1499
Group: Error
Name Estimate Lower Upper
{'Res Std'} 3.1361 3.0456 3.2293

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Analysis of Variance and Covariance en Help Center y File Exchange.

Productos


Versión

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by