MATLAB:使用不同的索引列表多次选择向量中的元素

4

输入:一个长度为 n 的逻辑行向量 u,例如 [1,0,1,1,0];以及一个大小为 m-by-n 的逻辑矩阵 M,例如 [1,0,0,1,1;0 0 0 1 1]

输出:一个大小为 m-by-n 的逻辑矩阵,其中第一行是通过将矩阵 M 的第一行应用为“选择器”而获得的,即 [1,0,0,1,0];,第二行类似地为 [0 0 0 1 0]

该行向量长度为20000,矩阵为30-by-20000。这将重复1000次,我希望找到一个耗时不到1秒的简单方法来“选择”这些元素,因为它们都是逻辑值。

我尝试过使用 repmatbsxfun 和逐元素乘法,但没有成功。猜测有一种简单的方法可以一次性“选择”这些元素,因为它们都是逻辑值。


根据n的大小和选择器u的稀疏程度,你得到的逻辑数组将主要是零,有许多行完全为零。你能否重新构思问题以利用这一点?你是否正在使用M来索引数据数组? - nicktruesdale
3个回答

1
目前我能提供的最快速度是4秒(在我的机器上)。我不确定你是否尝试过这个,但无论如何,这里有一个解决方案。
我有一个名为randbool.m的m文件,其中包含生成测试数据的内容。
function x = randbool(m,n)
x = logical(rand(m,n) < 0.5);

生成测试数据:

>> u = randbool(1,20000);
>> M = randbool(30,20000);

我可以想到三种方法来循环遍历M的行(使用bsxfun,使用repmat,使用循环),以及两种提取所需元素的方法(使用连接符&或使用点乘法.*)。最快的方法是将bsxfun和连接符结合起来使用:

Bsxfun / conjunction

>> tic, for i=1:1000, bsxfun(@and,u,M); end, toc
Elapsed time is 4.068684 seconds.

Bsxfun / 乘法

>> tic, for i=1:1000, bsxfun(@times,u,M); end, toc
Elapsed time is 4.856784 seconds.

Repmat / 连接

>> tic, for i=1:1000, utmp=repmat(u,30,1); M&utmp; end, toc
Elapsed time is 7.305158 seconds.

Repmat / 乘法

>> tic, for i=1:1000, utmp=repmat(u,30,1); M.*utmp; end, toc
Elapsed time is 8.117164 seconds.

循环/连接

>> tic, for i=1:1000, for j = 1:30, out(j,:)=u&M(j,:); end; end, toc
Elapsed time is 7.110872 seconds.

循环/乘法

>> tic, for i=1:1000, for j = 1:30, out(j,:)=u.*M(j,:); end; end, toc
Elapsed time is 8.322888 seconds.

+1 不错的总结。@DavidTan 注意:在bsxfun中,矩阵/向量参数的顺序对性能很重要。上述代码在我的电脑上比bsxfun(@and,M,u)快3倍。你可能需要小心。另外,Chris的原始版本在我的电脑上运行需要0.6秒。 - angainor

0

这看起来像是一个按位与操作。也许这样做会有帮助:

utemp=repmat(u,1,size(m,2));
output=M&utemp;

我应该补充说明,对于如此大的矩阵,您可能会遇到内存问题。基本上,您需要三份600K元素矩阵的副本,这可能会累加。

0

其他解决方案过于复杂。

你只需要将未选择的列中的条目清零即可...

M(:,~u)=0;

就是这样。只有十个微不足道的字符。Chris Taylor使用bsxfun和@and的解决方案稍微慢一些,其他方法更糟糕。

octave:8> u = logical(rand(1,20000)<0.5);
octave:9> M = logical(rand(30,20000)<0.5);
octave:10> tic, for i=1:1000, N=M; N(:,~u)=0; end, toc
Elapsed time is 0.66 seconds.
octave:11> tic, for i=1:1000, N=M; N=bsxfun(@and,u,N); end, toc
Elapsed time is 0.82 seconds.
octave:12> tic, for i=1:1000, N=bsxfun(@and,u,M); end, toc
Elapsed time is 0.8 seconds.

请注意,我使用了“N=M”来标准化结果,因为这种方法直接作用于向量,但赋值对时间没有任何显著影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接