Bu cevabın altında, for
döngülerden keyfi olarak kaçınmak yerine performansla ilgilendiğinizi açıkladınız .
Aslında, bence for
döngüler muhtemelen burada en performanslı seçenektir. "Yeni" (2015b) JIT motoru tanıtıldığından ( kaynak ) for
döngüler doğal olarak yavaş değildir - aslında dahili olarak optimize edilirler.
O Sen kriter görebilirsiniz mat2cell
ThomasIsCoding tarafından sunulan seçenek burada çok yavaş ...
Ölçeği daha net hale getirmek için bu çizgiden kurtulursak splitapply
, yöntemim oldukça yavaştır, obchardon'un akümülatör seçeneği biraz daha iyidir, ancak en hızlı (ve karşılaştırılabilir) seçenekler arrayfun
(Thomas tarafından da önerildiği gibi) veya bir for
döngü kullanır. Bunun çoğu kullanım durumu için kılık değiştirmiş arrayfun
bir for
döngü olduğuna dikkat edin , bu şaşırtıcı bir kravat değildir!
Daha for
fazla kod okunabilirliği ve en iyi performans için bir döngü kullanmanızı tavsiye ederim .
Düzenle :
Döngünün en hızlı yaklaşım olduğunu varsayarsak, find
komut etrafında bazı optimizasyonlar yapabiliriz .
özellikle
M
Mantıksal olun . Aşağıdaki çizimde görüldüğü gibi, bu nispeten küçük için daha hızlı olabilir M
, ancak büyükler için tür dönüşümünün değişmesi ile daha yavaş olabilir M
.
Kullanmak yerine M
diziyi dizine eklemek için bir mantıksal kullanın . Bu, döngünün en yavaş kısmını ( komut) önler ve tür dönüştürme yükünü ağırlaştırır, bu da onu en hızlı seçenek haline getirir.1:size(M,2)
find
find
İşte en iyi performans için önerim:
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
Bunu aşağıdaki karşılaştırmaya ekledim, işte döngü tarzı yaklaşımların karşılaştırması:
Karşılaştırma kodu:
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
döngülerden kaçınmasını mı istiyorsunuz ? Bu sorun için, modern MATLAB sürümlerinde, birfor
döngünün en hızlı çözüm olduğundan şüpheleniyorum . Bir performans sorununuz varsa, eski önerilere dayanan çözüm için yanlış yerde aradığınızdan şüpheleniyorum.