이 답변의 맨 아래에는 임의의 for
루프를 피하는 것이 아니라 성능에 관심이 있다는 것을 분명히 했으므로 벤치마킹 코드가 있습니다.
실제로 for
루프는 아마도 가장 성능이 좋은 옵션 이라고 생각 합니다. "새로운"(2015b) JIT 엔진이 도입 된 이후 ( 소스 ) for
루프는 본질적으로 느리지 않습니다. 실제로 내부적으로 최적화되어 있습니다.
것을 당신은 벤치 마크에서 볼 수 mat2cell
ThomasIsCoding에 의해 제공되는 옵션은 여기에 매우 느립니다 ...
우리가 스케일을 더 명확하게하기 위해 그 라인을 제거하면 내 splitapply
방법이 상당히 느리고 obchardon의 accumarray 옵션 이 조금 더 좋지만 가장 빠른 (그리고 비교 가능한) 옵션은 arrayfun
(Thomas가 제안한대로) 또는 for
루프를 사용하고 있습니다. 참고 arrayfun
기본적으로 인 for
이 놀라운 넥타이되지 않도록, 대부분의 사용 사례에 대한 변장 루프!
for
코드 가독성을 높이고 최상의 성능을 얻으려면 루프를 사용하는 것이 좋습니다 .
편집 :
루핑이 가장 빠른 방법이라고 가정하면 find
명령을 최적화 할 수 있습니다 .
구체적으로 특별히
M
논리적으로 만듭니다 . 아래 그림에서 알 수 있듯이 비교적 작은 M
경우에는 빠를 수 있지만 큰 경우에는 유형 변환의 절충으로 인해 느려질 수 있습니다 M
.
논리 M
를 사용하여 1:size(M,2)
대신 배열을 색인화 하십시오 find
. 이렇게하면 루프의 가장 느린 부분 ( find
명령)을 피하고 형식 변환 오버 헤드를 능가하여 가장 빠른 옵션이됩니다.
최상의 성능을위한 권장 사항은 다음과 같습니다.
function A = f_forlooplogicalindexing( M )
M = logical(M);
k = 1:size(M,2);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = k(M(r,:));
end
end
이것을 아래의 벤치 마크에 추가했습니다. 다음은 루프 스타일 방식의 비교입니다.
벤치마킹 코드 :
rng(904); % Gives OP example for randi([0,1],3)
p = 2:12;
T = NaN( numel(p), 7 );
for ii = p
N = 2^ii;
M = randi([0,1],N);
fprintf( 'N = 2^%.0f = %.0f\n', log2(N), N );
f1 = @()f_arrayfun( M );
f2 = @()f_mat2cell( M );
f3 = @()f_accumarray( M );
f4 = @()f_splitapply( M );
f5 = @()f_forloop( M );
f6 = @()f_forlooplogical( M );
f7 = @()f_forlooplogicalindexing( M );
T(ii, 1) = timeit( f1 );
T(ii, 2) = timeit( f2 );
T(ii, 3) = timeit( f3 );
T(ii, 4) = timeit( f4 );
T(ii, 5) = timeit( f5 );
T(ii, 6) = timeit( f6 );
T(ii, 7) = timeit( f7 );
end
plot( (2.^p).', T(2:end,:) );
legend( {'arrayfun','mat2cell','accumarray','splitapply','for loop',...
'for loop logical', 'for loop logical + indexing'} );
grid on;
xlabel( 'N, where M = random N*N matrix of 1 or 0' );
ylabel( 'Execution time (s)' );
disp( 'Done' );
function A = f_arrayfun( M )
A = arrayfun(@(r) find(M(r,:)),1:size(M,1),'UniformOutput',false);
end
function A = f_mat2cell( M )
[i,j] = find(M.');
A = mat2cell(i,arrayfun(@(r) sum(j==r),min(j):max(j)));
end
function A = f_accumarray( M )
[val,ind] = ind2sub(size(M),find(M.'));
A = accumarray(ind,val,[],@(x) {x});
end
function A = f_splitapply( M )
[r,c] = find(M);
A = splitapply( @(x) {x}, c, r );
end
function A = f_forloop( M )
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = find(M(r,:));
end
end
function A = f_forlooplogical( M )
M = logical(M);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = find(M(r,:));
end
end
function A = f_forlooplogicalindexing( M )
M = logical(M);
k = 1:size(M,2);
N = size(M,1);
A = cell(N,1);
for r = 1:N
A{r} = k(M(r,:));
end
end
for
? 아니면 루프 를 피하기 위해 결과를 원 하십니까? 이 문제의 경우 최신 버전의 MATLAB을 사용하면for
루프가 가장 빠른 솔루션이라고 생각합니다 . 성능 문제가있는 경우 오래된 조언을 기반으로 솔루션에 대한 잘못된 위치를 찾고 있다고 생각합니다.