首先,argyris 的矢量化解决方案可以很好地工作 (+1)。我发布这个只是因为你强调你想要一个速度优化的解决方案。好吧,argyris 解决方案的缺点是sum
andisnan
操作是在整个矩阵上执行的。如果您必须在任一侧走很长一段路才能找到第一个非 NaN 列,这将是最佳选择。但如果你不这样做呢?一个基于循环的解决方案利用您可能只需要进入几列这一事实可能会做得更好(特别是考虑到 JIT 加速器在快速执行单个循环方面有多好)。我整理了一个速度测试,其中包括 argyris 和我的解决方案:
%#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),我的解决方案仍然领先,但优势不如没有外部循环时那么大。
无论如何,希望这对您或其他任何来阅读的人有用。
干杯!
编辑:我做了一些速度测试,结合了 angainor 非常简洁的单线 (+1)。当要删除的列数很少时,它的性能几乎与我的基于循环的解决方案一样好。令人惊讶的是,与 argyris 的解决方案不同,当要删除的列数很大时,它的扩展性并不好。不过,这可能与我现在使用的计算机有关:工作 Windows 机器 - 我从来没有真正完全信任它 :-)