一个矩阵和一个包含索引的列向量,如何在没有循环的情况下进行迭代?

A matrix and a column vector containing indices, how to iterate with no loop?

我有一个大矩阵 (500212x7) 和一个列向量,如下所示

matrix F         vector P
0001011          4
0001101          3
1101100          6
0000110          1
1110000          7

该向量包含在矩阵行中考虑的索引。 P(1) 意味着指向 F(1,4),P(2) 指向 F(2,3) 等等。

我想取反 P 元素指向的列(在同一行)中 F 的每一行中的一个位。

我想到了

F(:,P(1)) = ~F(:,P(1));
F(:,P(:)) = ~F(:,P(:));

但当然这些场景不会产生我期望的结果,因为第一行不会使 P 元素发生变化,第二行甚至不会让我启动程序,因为完整的向量无法创建索引.

我的想法是我需要对所有 F 和 P 行 (changing/incrementing "simultaneously") 执行此操作,但取 P 元素的 value

我知道这很容易通过 for 循环实现,但是由于 F 数组的尺寸很大,这种解决问题的方法是完全不能接受的。

是否有任何类型的 Matlab 魔法可以使用矩阵运算来解决此类任务?

不确定它是否符合 wizardry,但 linear indexing 完全符合您的要求:

F = [0 0 0 1 0 1 1; 0 0 0 1 1 0 1; 1 1 0 1 1 0 0; 0 0 0 0 1 1 0; 1 1 1 0 0 0 0];
P = [4; 3; 6; 1; 7];
ind = (1:size(F,1)) + (P(:).'-1)*size(F,1); % create linear index
F(ind) = ~F(ind); % negate those entries

I know this is easily achieved with for loop but due to large dimensions of the F array such a way to solve the problem is completely unacceptable.

你永远不应该做出这样的假设。首先实现循环,然后检查它是否真的对你来说太慢了,然后再考虑优化。

我在这里比较 和简单的循环:

N = 500212;
F = rand(N,7) > 0.6;
P = randi(7,N,1);

timeit(@()method1(F,P))
timeit(@()method2(F,P))

function F = method1(F,P)
   ind = (1:size(F,1)) + (P(:).'-1)*size(F,1); % create linear index
   F(ind) = ~F(ind); % negate those entries
end

function F = method2(F,P)
   for ii = 1:numel(P)
      F(ii,P(ii)) = ~F(ii,P(ii));
   end
end

Luis 的回答时间为 0.0065 秒,循环时间为 0.0023 秒 (MATLAB Online R2019a)。

对于非常大的数组,尤其是,如果向量化需要创建中间数组,循环比向量化代码更快。内存访问很昂贵,使用更多内存会使代码变慢。

经验教训:不要拒绝循环,不要过早地尝试优化,不要在没有比较的情况下进行优化。

另一个解决方案:

xor( F, 1:7 == P )

解释:

  • 1:7 == P 生成单热数组。
  • xor 将导致位保留其值对 0,并翻转它对 1