一个矩阵和一个包含索引的列向量,如何在没有循环的情况下进行迭代?
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
我有一个大矩阵 (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