From: happydude on
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
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
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
"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
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.
 |  Next  |  Last
Pages: 1 2
Prev: mxArray ou mwArray?
Next: Color recognition