Azzera filtri
Azzera filtri

Trouble vectorising a loop

2 visualizzazioni (ultimi 30 giorni)
Rhys
Rhys il 9 Lug 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.

Risposta accettata

Matt J
Matt J il 9 Lug 2013
Modificato: Matt J il 9 Lug 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 Commenti
Matt J
Matt J il 10 Lug 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 il 11 Lug 2013
Thanks Matt, chopping the unused columns out of the calculation really does the trick!

Accedi per commentare.

Più risposte (2)

Matt J
Matt J il 9 Lug 2013
Modificato: Matt J il 9 Lug 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 il 11 Lug 2013
Modificato: Jan il 11 Lug 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.

Categorie

Scopri di più su Loops and Conditional Statements in Help Center e File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by