Here is my vectorization of your function. I worked from the inside out and commented on earlier versions when I went. So the first loop that I have vectorized has ### comment marks.
This is not as clean and sound as @Andras's answer, but I hope it is educational, giving an idea of how you can solve this problem gradually.
def foo2(data, threshold): CM_tilde = np.mean(data, axis=1) N = data.shape[1] #data_cm = np.zeros(( data.shape[0], data.shape[1], data.shape[2] )) ##all_CMs = np.zeros(( data.shape[0], data.shape[2])) bmask = data < (CM_tilde[:,None,:] + threshold) CM = np.zeros_like(data) CM[:] = CM_tilde[:,None,:] CM[bmask] = data[bmask] CM = CM.sum(axis=1) CM = CM/N all_CMs = CM.copy() """ for frame in range(data.shape[2]): for row in range(data.shape[0]): ###print(frame, row) ###mask = data[row, :, frame] < (CM_tilde[row, frame]+threshold) ###print(mask) ##mask = bmask[row,:,frame] ##CM = data[row, mask, frame].sum() ##CM += (CM_tilde[row, frame]*(~mask)).sum() ##CM = CM/N ##all_CMs[row, frame] = CM ## calculate CM corrected value #for col in range(data.shape[1]): # data_cm[row, col, frame] = data[row, col, frame] - CM[row,frame] print "frame: ", frame """ data_cm = data - CM[:,None,:] return data_cm, all_CMs
The output matches for this small test case, which more than helped me get the right sizes.
threshold = .1 data = np.arange(4*3*2,dtype=float).reshape(4,3,2)