Hi all,
I'm trying to vectorize the following loop to speed it up
c = cumsum(weights);
A = ones(1,n);
x = rand(1,n);
for i = 1:n
j = find(c > x(i) ,1,'first');
A(i) = j;
end
where weights is an array of doubles which sum to 1 and n <= size(weights).
Any help would be grand!
B

 채택된 답변

Oleg Komarov
Oleg Komarov 2011년 4월 13일

3 개 추천

n = 3e4;
weights = rand(n,1);
c = cumsum(weights/sum(weights));
A = zeros(1,n);
x = rand(1,n);
tic
for i = 1:n
j = find(c > x(i) ,1,'first');
A(i) = j;
end
toc
% WARNING: only if weights are monotonically increasing
tic
[B1,B1] = histc(x,c);
toc
tic
B2 = n-sum(bsxfun(@gt,c,x))+1; % Goes fast in out of memory
toc
isequal(A,B1+1,B2) % Don't forget to add 1 to histc result
LOOP : Elapsed time is 2.247998 seconds.
HISTC : Elapsed time is 0.005381 seconds.
BSXFUN: Elapsed time is 1.770875 seconds.

댓글 수: 4

Sean de Wolski
Sean de Wolski 2011년 4월 13일
Nice!
Andrew Newell
Andrew Newell 2011년 4월 13일
In recent versions of MATLAB you can use
[~,B1] = histc(x,c)
(but it doesn't make it any faster).
Matt Fig
Matt Fig 2011년 4월 13일
Well-played, Oleg!
Jan
Jan 2012년 6월 28일
accepted by JSimon

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Sean de Wolski
Sean de Wolski 2011년 4월 13일

0 개 추천

Note sure if it'll be faster but:
[row col] = find(bsxfun(@gt,c(:)',x(:)));
A2 = accumarray(row,col,[],@min)';

댓글 수: 2

Matt Fig
Matt Fig 2011년 4월 13일
Your intuition is correct. On my machine this is 50 times slower than the simple loop, using:
A = magic(1000);
weights = A(1,:)/sum(A(1,:));
n = 1000;
Sean de Wolski
Sean de Wolski 2011년 4월 13일
It would only get slower as the matrices get bigger. I think Ben's elementary, but properly constructed, FOR-loop is probably optimal.
I just realized and am kind of surprised FIND doesn't have a dimensional argument.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터 및 File Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by