把一个二矩阵变成一个矢量的最后一个非零的索引,矢量的时尚
-
06-07-2019 - |
题
假设,在MATLAB,我有一个矩阵,一个,其元素都是0或1。
我怎么得到的矢量指数的最后一个非零件的每个列在一个速度更快,矢量的方式?
我可以做的
[B, I] = max(cumsum(A));
和使用 I
, 但是有一个更快速方式?(我假设cumsum会花费一点时间甚至素明0和1)。
编辑: 我想我矢量的甚至比我更需要的快先生Fooz'循环是巨大的,但每个环MATLAB中似乎成本 我 很多在调试的时间,即使它是快。
解决方案
如由 先生Fooz, 为循环,可以很快与较新版本的MATLAB。但是,如果你真的想要有紧凑的矢量的代码,我建议试图:
[B,I] = max(flipud(A));
I = size(A,1)-I+1;
这是速度比你的CUMSUM基于答案,但仍然不是很快,先生Fooz的循环的选择。
另外两个要考虑的事项:
什么样的结果,你想要得到的列有没有人在这吗?与上述的选择我给了你,我相信你会得到一个指数 大小(1) (即行数 一个)在这样的情况。为你的选项,我相信,你将获得1在这样的情况,而嵌套循环的选择从先生Fooz会给你一个0.
相对速度的这些不同的选项很可能会根据不同大小的 一个 并非零你指望它有。
其他提示
快速是你应该担心的,不一定是完全矢量化。 Matlab的最新版本对于有效处理循环非常聪明。如果有一种紧凑的矢量化表达方式,它通常会更快,但循环不应该(总是)像以前那样担心。
clc
A = rand(5000)>0.5;
A(1,find(sum(A,1)==0)) = 1; % make sure there is at least one match
% Slow because it is doing too much work
tic;[B,I1]=max(cumsum(A));toc
% Fast because FIND is fast and it runs the inner loop
tic;
I3=zeros(1,5000);
for i=1:5000
I3(i) = find(A(:,i),1,'last');
end
toc;
assert(all(I1==I3));
% Even faster because the JIT in Matlab is smart enough now
tic;
I2=zeros(1,5000);
for i=1:5000
I2(i) = 0;
for j=5000:-1:1
if A(j,i)
I2(i) = j;
break;
end
end
end
toc;
assert(all(I1==I2));
在R2008a,Windows,x64上,cumsum版本需要0.9秒。循环和查找版本需要0.02秒。双循环版仅需0.001秒。
编辑:哪一个最快取决于实际数据。当你将0.5改为0.999时,双循环需要0.05秒(因为它需要更长的时间才能达到平均值)。 cumsum和loop& find实现具有更加一致的速度。
编辑2: gnovice的flipud解决方案很聪明。不幸的是,在我的测试机器上需要0.1秒,所以它比cumsum快得多,但比循环版本慢。