まず、argyrisのベクトル化されたソリューションは完全にうまく機能します(+1)。速度が最適化されたソリューションが必要だと強調されたため、これを投稿するだけです。さて、アージリス解の欠点は、sum
とisnan
操作が行列全体で実行されることです。これは、最初の非NaNカラムを見つけるためにどちらかの側に長い道のりをたどる必要がある場合に最適です。しかし、そうでない場合はどうなりますか?数列に入るだけでよいという事実を利用するループベースのソリューションの方がうまくいく可能性があります(特に、JITアクセラレーターが単一ループを迅速に実行するのにどれだけ優れているかを考えると)。アージリスと私のソリューションの両方を含む速度テストをまとめました。
%#Set up an example case using the matrix size you indicated in the question
T = 30;
N = 26000;
X = rand(T, N);
TrueL = 8;
TrueR = N - 8;
X(:, 1:TrueL) = NaN;
X(:, TrueR:end) = NaN;
%#argyris solution
tic
I1 = sum(isnan(X));
argL = find(I1 == 0, 1, 'first');
argR = find(I1 == 0, 1, 'last');
Soln1 = X(:, argL:argR);
toc
%#My loop based solution (faster if TrueL and TrueR are small)
tic
for n = 1:N
if ~any(isnan(X(:, n)))
break
end
end
ColinL = n;
for n = N:-1:1
if ~any(isnan(X(:, n)))
break
end
end
ColinR = n;
Soln2 = X(:, ColinL:ColinR);
toc
上記の例では、ソリューションは最初の8列と最後の8列を削除する必要があります。スピードテストの結果は?
Elapsed time is 0.002919 seconds. %#argyris solution
Elapsed time is 0.001007 seconds. %#My solution
ループベースのソリューションは、ほぼ3倍高速です。では、どちらかの側で削除する必要のある列の数を100に増やしましょう。
Elapsed time is 0.002769 seconds. %#argyris solution
Elapsed time is 0.001999 seconds. %#My solution
まだ先です。両側の1000列はどうですか?
Elapsed time is 0.003597 seconds. %#argyris solution
Elapsed time is 0.003719 seconds. %#My solution
だから私たちは転換点を見つけました(少なくとも私のマシンでは-クアッドコアi7、Linux Mint v12、Matlab R2012b)。どちらかの側に約1000列を入力する必要がある場合は、ベクトル化されたソリューションを使用することをお勧めします。
注意の最後の注意:ルーチンが別の(おそらく無関係の)ループ内で発生している場合は、速度の比較をやり直す必要があります。これは、私のソリューションにダブルループが含まれるようになるためです。ループが無関係であっても、JITアクセラレーターは二重ループではあまり良くありません。私は自分のマシンでいくつかの簡単なテストを行いましたが、小さなTrueLとTrueR(つまり、100未満)のソリューションはまだ先に出ていますが、外側のループが存在しない場合ほど大きな利点はありません。
とにかく、これがあなたや読書に来る他の人に役立つことを願っています。
乾杯!
編集:私は、アナガーの非常にきちんとしたワンライナー(+1)を組み込んだいくつかの速度テストを行いました。削除する列の数が少ない場合は、ループベースのソリューションとほぼ同じように機能します。驚いたことに、アージリスのソリューションとは異なり、削除する列の数が多い場合は、それほど適切にスケーリングされませんでした。それは私が今使っているコンピュータと関係があるかもしれません:Windowsマシンを動かしてください-私はそれを完全に信頼したことはありません:-)