Trouble vectorising a loop

1 view (last 30 days)
Rhys
Rhys on 9 Jul 2013
I'm trying to tidy up and improve some of my code and have come across a loop that I am struggling to vectorise. I am calculating the mean value of specific parts of a matrix and replacing certain values within the matrix with the newly calculated values.
For example, if I have a matrix 'A' I would like to replace element A(3,1) with the mean of A(2,1) and A(3,1). Likewise, I would then like to replace A(3,2) with the mean of A(2,2) and A(3,2) and so on (although I don't want to do this for every single column, just specific ones). This process is also repeated at various other locations in the matrix (i.e. also replace A(6,1) with the mean of A(5,1) and A(6,1) and so on).
The looped version of my code is of the following form:
A = rand(7,6);
firstRows=[2;5];
lastRows=[3;6];
columnIndicies=[1 2 3];
A2=A;
for j=1:1:length(lastRows)
A2(lastRows(j),columnIndicies)= ...
mean(A((firstRows(j)):(lastRows(j)),columnIndicies),1);
end
A3 = A2(lastRows,:);
Any comments / assistance would be much appreciated.

Accepted Answer

Matt J
Matt J on 9 Jul 2013
Edited: Matt J on 9 Jul 2013
J=arrayfun(@(a,b) (a:b), firstRows,lastRows,'uni',0);
I=cellfun(@(a,b)ones(1,length(a))*b ,J.',num2cell(1:length(J)),'uni',0);
S=cellfun(@(a,b)ones(1,length(a))/length(a) ,J,'uni',0);
B=sparse([I{:}],[J{:}],[S{:}],length(lastRows),size(A,1));
A2=A;
A2(lastRows,columnIndices)=B*A(:,columnIndices);
  8 Comments
Matt J
Matt J on 10 Jul 2013
Rhys, see my most recent version (and timing comparison) above. Chopping out the unused columns of A helped a lot. My version exceeded the for-loops signficantly, even including the cellfun calls.
Rhys
Rhys on 11 Jul 2013
Thanks Matt, chopping the unused columns out of the calculation really does the trick!

Sign in to comment.

More Answers (2)

Matt J
Matt J on 9 Jul 2013
Edited: Matt J on 9 Jul 2013
idx=false(size(A));
idx1=idx; idx1(firstRows,columnIndices)=1;
idx2=idx; idx2(lastRows,columnIndices)=1;
A2=A;
A2(idx2)=(A(idx1)+A(idx2))/2;

Jan
Jan on 11 Jul 2013
Edited: Jan on 11 Jul 2013
Another idea:
S = cumsum(A, 1);
B = S(lastRows, :) - S(firstRows - 1, :);
A0(lastRows, :) = bsxfun(@rdivide, B, lastRows - firstRows + 1);
Three problems: 1. I cannot test this currently, and I frequently confuse -1 and +1. 2. The exception firstRows==1 must be handled. 3. CUMSUM accumulates rounding errors and you have to check, if the accuracy of the results satisfies your needs.
Benefit: It avoid calculating the sum of neighboring elements multiple times in case of overlapping intervals.

Categories

Find more on Function Creation in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!