@@ -86,20 +86,41 @@ def _list_outputs(self):
86
86
return outputs
87
87
88
88
89
- def ICC_rep_anova (Y ):
89
+ def ICC_rep_anova (Y , nocache = False ):
90
90
"""
91
91
the data Y are entered as a 'table' ie subjects are in rows and repeated
92
92
measures in columns
93
-
94
93
One Sample Repeated measure ANOVA
95
-
96
94
Y = XB + E with X = [FaTor / Subjects]
97
- """
98
95
99
- [nb_subjects , nb_conditions ] = Y .shape
100
- dfc = nb_conditions - 1
101
- dfe = (nb_subjects - 1 ) * dfc
102
- dfr = nb_subjects - 1
96
+ This is a hacked up (but fully compatible) version of ICC_rep_anova
97
+ from nipype that caches some very expensive operations that depend
98
+ only on the input array shape - if you're going to run the routine
99
+ multiple times (like, on every voxel of an image), this gives you a
100
+ HUGE speed boost for large input arrays. If you change the dimensions
101
+ of Y, it will reinitialize automatially. Set nocache to True to get
102
+ the original, much slower behavior. No, actually, don't do that.
103
+ """
104
+ global icc_inited
105
+ global current_Y_shape
106
+ global dfc , dfe , dfr
107
+ global nb_subjects , nb_conditions
108
+ global x , x0 , X
109
+ global centerbit
110
+
111
+ try :
112
+ current_Y_shape
113
+ if nocache or (current_Y_shape != Y .shape ):
114
+ icc_inited = False
115
+ except NameError :
116
+ icc_inited = False
117
+
118
+ if not icc_inited :
119
+ [nb_subjects , nb_conditions ] = Y .shape
120
+ current_Y_shape = Y .shape
121
+ dfc = nb_conditions - 1
122
+ dfe = (nb_subjects - 1 ) * dfc
123
+ dfr = nb_subjects - 1
103
124
104
125
# Compute the repeated measure effect
105
126
# ------------------------------------
@@ -109,20 +130,22 @@ def ICC_rep_anova(Y):
109
130
SST = ((Y - mean_Y ) ** 2 ).sum ()
110
131
111
132
# create the design matrix for the different levels
112
- x = kron (eye (nb_conditions ), ones ((nb_subjects , 1 ))) # sessions
113
- x0 = tile (eye (nb_subjects ), (nb_conditions , 1 )) # subjects
114
- X = hstack ([x , x0 ])
133
+ if not icc_inited :
134
+ x = kron (eye (nb_conditions ), ones ((nb_subjects , 1 ))) # sessions
135
+ x0 = tile (eye (nb_subjects ), (nb_conditions , 1 )) # subjects
136
+ X = hstack ([x , x0 ])
137
+ centerbit = dot (dot (X , pinv (dot (X .T , X ))), X .T )
115
138
116
139
# Sum Square Error
117
- predicted_Y = dot (dot ( dot ( X , pinv ( dot ( X . T , X ))), X . T ) , Y .flatten ("F" ))
140
+ predicted_Y = dot (centerbit , Y .flatten ("F" ))
118
141
residuals = Y .flatten ("F" ) - predicted_Y
119
142
SSE = (residuals ** 2 ).sum ()
120
143
121
144
residuals .shape = Y .shape
122
145
123
146
MSE = SSE / dfe
124
147
125
- # Sum square session effect - between colums /sessions
148
+ # Sum square session effect - between columns /sessions
126
149
SSC = ((mean (Y , 0 ) - mean_Y ) ** 2 ).sum () * nb_subjects
127
150
MSC = SSC / dfc / nb_subjects
128
151
@@ -134,9 +157,11 @@ def ICC_rep_anova(Y):
134
157
135
158
# ICC(3,1) = (mean square subjeT - mean square error) /
136
159
# (mean square subjeT + (k-1)*-mean square error)
137
- ICC = ( MSR - MSE ) / (MSR + dfc * MSE )
160
+ ICC = nan_to_num (( MSR - MSE ) / (MSR + dfc * MSE ) )
138
161
139
162
e_var = MSE # variance of error
140
163
r_var = (MSR - MSE ) / nb_conditions # variance between subjects
141
164
165
+ icc_inited = True
166
+
142
167
return ICC , r_var , e_var , session_effect_F , dfc , dfe
0 commit comments