Filter löschen
Filter löschen

Vectorize for-loop that changes overlapping parts of an array

2 Ansichten (letzte 30 Tage)
Hi everyone,
I have problem speeding up my code. I have a very large (20-40m datapoints) logical array and at every position where it reads "1", the next N datapoints should be set to "1" a well.
I have the following code that is quite slow since it has a for loop:
N=5000-1;
logarray; %logical array of size 40000000x1
inx=find(logarray); %inx can be quite large as well, 1-5m points
for ii=1:length(inx)
logarray(inx(ii):(inx(ii)+N))=1;
end
This code works, but is very slow (more than 10 secs). I tried something like
logarray(find(inx):(find(inx)+100))=1;
but this did not work. I was wondering whether vectorisation would be a solution here? Mind that overlapping parts of the logical array are changed by the loop.
Does anyone have a good suggestion?
Thanks, Maximilian

Akzeptierte Antwort

Jos (10584)
Jos (10584) am 20 Apr. 2016
Bearbeitet: Jos (10584) am 20 Apr. 2016
Easy when using convolution:
logarray = logical([0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1])
N = 2 ;
out = conv2(double(logarray(:)), ones(N+1,1)) ;
out = out(1:numel(logarray))>0 ;
out = reshape(out,size(logarray)) ;
disp([logarray(:) ; out(:)]) ;
  2 Kommentare
Jos (10584)
Jos (10584) am 20 Apr. 2016
taking about 2 seconds on my old mac for a 3e7 elements and N = 5000

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Roger Stafford
Roger Stafford am 20 Apr. 2016
Bearbeitet: Roger Stafford am 20 Apr. 2016
It isn't perhaps that you have a for-loop that is slowing you down so much as that your loop is repeating the writing of ones so much in overlapping intervals. You might try the following which first combines overlapping intervals before doing the writing of ones.
N=5000-1;
f1 = find(logarray);
f2 = min(f1+N,length(logarray));
f3 = zeros(size(f1));
f4 = zeros(size(f2));
ie = 1;
f3(ie) = f1(ie);
f4(ie) = f2(ie);
for ib = 1:size(f1,1)-1
if f1(ib+1) > f4(ie)+1
ie = ie+1;
f3(ie) = f1(ib+1);
end
f4(ie) = f2(ib+1);
end
f3 = f3(1:ie); % The intervals defined by f3 and f4 don't overlap
f4 = f4(1:ie);
for ib = 1:ie
logarray(f3(ib):f4(ib)) = 1;
end
  1 Kommentar
Roger Stafford
Roger Stafford am 20 Apr. 2016
I thought of another way you could try which uses 'accumarray'. Assume 'logarray' is a column vector.
N = 1000;
f = find(logarray);
t = ones(size(f));
logarray = min(cumsum(accumarray([f;f+N+1],[t;-t],...
[length(logarray)+N+1,1])),1);
logarray(end) = [];

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Creating and Concatenating Matrices finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by