@@ -86,20 +86,41 @@ def _list_outputs(self):
8686 return outputs
8787
8888
89- def ICC_rep_anova (Y ):
89+ def ICC_rep_anova (Y , nocache = False ):
9090 """
9191 the data Y are entered as a 'table' ie subjects are in rows and repeated
9292 measures in columns
93-
9493 One Sample Repeated measure ANOVA
95-
9694 Y = XB + E with X = [FaTor / Subjects]
97- """
9895
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
103124
104125 # Compute the repeated measure effect
105126 # ------------------------------------
@@ -109,20 +130,22 @@ def ICC_rep_anova(Y):
109130 SST = ((Y - mean_Y ) ** 2 ).sum ()
110131
111132 # 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 = X @ pinv (X .T @ X , hermitian = True ) @ X .T
115138
116139 # Sum Square Error
117- predicted_Y = X @ ( pinv ( X . T @ X , hermitian = True ) @ ( X . T @ Y .flatten ("F" )) )
140+ predicted_Y = centerbit @ Y .flatten ("F" )
118141 residuals = Y .flatten ("F" ) - predicted_Y
119142 SSE = (residuals ** 2 ).sum ()
120143
121144 residuals .shape = Y .shape
122145
123146 MSE = SSE / dfe
124147
125- # Sum square session effect - between colums /sessions
148+ # Sum square session effect - between columns /sessions
126149 SSC = ((mean (Y , 0 ) - mean_Y ) ** 2 ).sum () * nb_subjects
127150 MSC = SSC / dfc / nb_subjects
128151
@@ -139,4 +162,6 @@ def ICC_rep_anova(Y):
139162 e_var = MSE # variance of error
140163 r_var = (MSR - MSE ) / nb_conditions # variance between subjects
141164
165+ icc_inited = True
166+
142167 return ICC , r_var , e_var , session_effect_F , dfc , dfe
0 commit comments