Prev: mxArray ou mwArray?
Next: Color recognition
From: happydude on 23 Nov 2009 12:22 i have a column vector of 1's and 0's and a corresponding column of numbers I would like to cumsum. However, for each instance of there being a "1" i would like to restart a cumsum from scratch (the original vector is massive. I want to avoid doing this with loops). How can you do this? the sample data is a two column matrix, a vector of 1's and a vector of numbers : x = [1,90;0,108;1,-138;0,12;1,66;1,150;1,-270;0,-24;0,24;0,0;0,-120;0,42;0,48;1,228;1,192;1,36;0,-84;0,168;]; The result I want is ths x(:,3) = [90;NaN;-138;NaN;66;216;-54;NaN;NaN;NaN;NaN;NaN;NaN;228;420;456;NaN;NaN;] basically NaN's whenever there is a zero and a restarted cumsum whenever there is a 1. Finding a cumsum for the days where there are 1's is easy enough, but how to restart the cumsum from zero?? Help greatly appreciated! :)
From: Bruno Luong on 23 Nov 2009 13:41 x = [1,90;0,108;1,-138;0,12;1,66;1,150;1,-270;0,-24;0,24;0,0;0,-120;0,42;0,48;1,228;1,192;1,36;0,-84;0,168;]; % Engine cx1=cumsum(x(:,2)); cx2=zeros(size(cx1)); i=findstr([0 x(:,1).'],[0 1]); cx2(i)=diff([0; cx1(i)-x(i,2)]); x3=cx1-cumsum(cx2); x3(~x(:,1)) = NaN; [x x3] % Bruno
From: Matt Fig on 23 Nov 2009 15:20 Like Bruno showed, I don't see a way to both do this quickly and avoid cumsumming two times. Another alternative is to write a custom mex function, which in this case is pretty easy. Note, I am not a C guy, so this may not be the most efficient way to write the code, but it is more than twice as fast as cumsumming twice for large inputs. MEX the function, then use it like this: tmp = x(:,2); tmp(~x(:,1)) = NaN; tmp = cumsum_nan(tmp); # include "mex.h" # include "matrix.h" // CUMSUM_NAN.CPP // Speciality CUMSUM which treats NaN values as a reset to the cumsum. void mexFunction( int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) { int row, col; double *INP, *OUP; int hh; row = mxGetM(prhs[0]); col = mxGetN(prhs[0]); INP = mxGetPr(prhs[0]); plhs[0] = mxCreateDoubleMatrix(row,col,mxREAL); OUP = mxGetPr(plhs[0]); for (int jj = 0; jj < col; jj++) *(OUP + row*jj ) = *(INP + row*jj ); for (int ii = 1; ii<row; ii++) { for (int jj = 0; jj < col; jj++) { hh = row*jj + ii; if (mxIsNaN(*(INP + hh - 1))) *(OUP + hh) = *(INP + hh); else { if (mxIsNaN(*(INP + hh))) *(OUP + hh) = *(INP + hh); else *(OUP + hh) = *(OUP + hh - 1) + *(INP + hh); } } } }
From: Bruno Luong on 23 Nov 2009 15:40 "Matt Fig" <spamanon(a)yahoo.com> wrote in message <heeqq2$ebg$1(a)fred.mathworks.com>... > Like Bruno showed, I don't see a way to both do this quickly and avoid cumsumming two times. Another alternative is to write a custom mex function, which in this case is pretty easy. Note, I am not a C guy, so this may not be the most efficient way to write the code, but it is more than twice as fast as cumsumming twice for large inputs. I'm sure you knew the answer Matt: How Matlab for-loop perform? Bruno
From: Matt Fig on 23 Nov 2009 16:20
Funny, Bruno. I didn't even bother to check till you said something. The ML For loop performs about as fast as the mex I wrote. LOL. Now a mex which took the whole x in and spit out the new 3 col x might be the one to beat. |