-
Notifications
You must be signed in to change notification settings - Fork 27
/
GenOrthogComps.m
128 lines (115 loc) · 4.94 KB
/
GenOrthogComps.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
function [M,MList]=GenOrthogComps(nTreats,NormFlag)
%function [M,MList]=GenOrthogComps(nTreats,NormFlag)
%
%This will generate coefficients corresponding to one particular set of
%orthogonal comparisons for a set of variables, given an input degrees of
%freedom for each variable.
%
%This is used for multiple comparisons following anova's as well as in the
%huynh-feldt corrections for repeated measures anovas
%
% Inputs:
% df - a vector of variable length denoting the degrees of freedom
% (as in num treatments-1) for each factor. The length of dfs
% is the number of factors
% NormFlag - set to 1 or 0 to determine wether or not you want to
% normalize the output coefficients. normalization happens so
% that the sum of the squares of each row of each output
% matrix sum to 1. Defaults to 1.
%
% Outputs:
% Mout - this is a cell array of a matrix of coefficients
% corresponding to the matrices M in the Huynh article from
% 1978 that correspond to each main effect and each interaction.
%
% For example, if nTreats= [3], meaning one factor with 3
% different levels, the ouput will be: M= [1 -1 0;
% 1/2 1/2 -1]
% which corresponds to the first comparison of u1-u2 and a
% second orthogonal copmarison of 1/2*u1 + 1/2*u2 -u3
%
% Main effects are presented in the first Mout, followed by
% interactions, starting with 2 way interactions of the first
% two factors, then 3 way interactions after all the 2-way
% interactions, etc.
%
% MList This is a cell array of a text list of the effects for the
% corresponding matrices in M. for example 'A' means main
% effect for the first factor, 'AB' means a 2way interaction
% for the first two factors, etc.
%
% To get the matrices needed for the Huynh-Feldt correction, only
% input the nTreats for all of the within subject factors in your
% design.
%
% Note this outputs one (relatively easy) way to get orthogonal
% copmarisons, but be aware that tere are infinite different ways to come
% up with a set of orthogonal copmarisons.
%
% For exapmle, running GenOrthogComps([3 3]) give identical outputs to the
% M matrices of table 1 in Huynh H. (1978) "Some approximate tests for repeated
% measurement designs", Psychometrika
%
% written on 090131 by Matthew Nelson
if nargin<2 || isempty(NormFlag); NormFlag=1; end
alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'; %used for MList. If you have more than 26 factors this will result in an error, but if your expeirmental design has more than 26 factors, you may need to stop and rethink a whole number of things
dfs=nTreats-1;
nFacs=length(nTreats);
nCombs=prod(nTreats);
%first do comps for main effects
M=cell(1,nFacs);
for iFac=1:nFacs
M{iFac}=repmat(0,dfs(iFac),nCombs);
if iFac==nFacs; nLowCombs=1;
else nLowCombs=prod(nTreats(iFac+1:end));
end
if iFac==1; nUpCombs=1;
else nUpCombs=prod(nTreats(1:iFac-1));
end
for idf=1:dfs(iFac)
tmpComps=repmat( 0,1,nLowCombs*nTreats(iFac) );
tmpComps( 1:nLowCombs*idf )=1/idf;
tmpComps( nLowCombs*idf+1:nLowCombs*(idf+1) )=-1;
tmpComps=repmat(tmpComps,1,nUpCombs);
M{iFac}(idf, : )=tmpComps;
MList{iFac}=alphabet(iFac);
end
end
%Now do comps for any interactions as products of the main effect comps ...
%I believe this requires recursion
if nFacs>1
for curnFacs=2:nFacs %start with 2 way interactions and go up to nFacs-way interactions
for initFac=1:nFacs-(curnFacs-1)
[M MList]=RLoop(curnFacs,initFac,repmat(1,1,nCombs), length(M)+1, '', M,MList,dfs,alphabet);
end
end
end
%optionally normalize coefficients
if NormFlag
for im=1:length(M)
for ir=1:size(M{im},1)
M{im}(ir,:)=M{im}(ir,:)/ sqrt((sum(M{im}(ir,:).^2)));
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [M MList]=RLoop(FacRem,curFac,curRow,curMNum, nextList, M,MList,dfs,alphabet)
%given the initial inputs, and the initial curFac, this should calc all the
%downstream M vals for that initial curFac...
FacRem=FacRem-1;
for idf=1:dfs(curFac)
if FacRem==0
if curMNum>length(M);
M{curMNum}=[];
MList{curMNum}=[nextList alphabet(curFac)];
end
M{curMNum}(end+1,:)=curRow.*M{curFac}(idf,:);
else
nextRow=curRow.*M{curFac}(idf,:);
nextList(end+1)=alphabet(curFac);
baseFacNum=curFac+1; %this is needed for the numbering of the outputs...
for iNextFac=curFac+1:length(dfs)-FacRem+1
[M MList]=RLoop( FacRem,iNextFac,nextRow,curMNum+(iNextFac-baseFacNum), nextList, M,MList,dfs,alphabet );
end
end
end