我有一个矩阵M(4 * 2),值为:
[1 0;
0 0;
1 1;
0 1]
数组X = [0.3 0.4 0.5 0.2];
M
的所有列条目都是二进制(0/1)。我想要的是映射到名为[2,2]
的{{1}}的ND阵列的相应行值。这里的每个维度表示0/1,通过将其放在第一行或第二行中。 Z
需要转到X(1)
,Z(2,1)
需要转到X(2)
等等。
Z将如下所示:
Z(1,1)
目前我正在循环使用它,但这样做真的很贵。请注意,这是一个最小的例子 - 我需要将这个128 * 7矩阵转换为7D阵列。
有关如何加快此过程的任何建议?
答案 0 :(得分:2)
您可以尝试使用accumarray(不确定它是否更快):
>> Z = accumarray(M + 1, X, [2 2])
Z =
0.4000 0.2000
0.2000 0.5000
答案 1 :(得分:1)
怎么样
D=[1 0;0 0;1 1;0 1]; X = [0.3 0.4 0.5 0.2];
Z(sub2ind([2 2], D(:, 1) + 1, D(:, 2) + 1)) = X;
Z = reshape(Z, 2, 2);
修改的
不幸的是,sub2ind的大部分开销都是错误检查。如果您觉得所有D值都在范围内,则可以有效地内联sub2ind操作。这是一个例子:
ndx = M(:, 1) + 1;
ndx = ndx + M(:, 2) * 2;
Z2=[];
Z2(ndx) = X;
Z2 = reshape(Z2, 2, 2);
在@ johnnyfuego的答案中使用此代码和时间测试,我得到了
Elapsed time is 0.154196 seconds. <--- johnny's
Elapsed time is 0.288680 seconds. <--- mine
Elapsed time is 0.143874 seconds.
所以,更好,但仍未击败其他两个。但请注意,这里有一个收支平衡点。如果我将时间测试中的设置代码更改为
M = randi(2, 1000, 2) - 1;
X = rand(1, 1000);
也就是说,我将要写入的值的数量从4增加到1000,然后计时器结果为
Elapsed time is 3.650833 seconds. <--- johnny's
Elapsed time is 0.607361 seconds. <--- mine
Elapsed time is 0.872595 seconds.
编辑#2
以下是展开多维sub2ind的方法:
siz = [2 2 2 2 2 2 2];
offsets = cumprod(siz);
ndx = M(:, 1) + 1;
ndx = ndx + M(:, 2) * offsets(1);
ndx = ndx + M(:, 3) * offsets(2);
ndx = ndx + M(:, 4) * offsets(3);
ndx = ndx + M(:, 5) * offsets(4);
ndx = ndx + M(:, 6) * offsets(5);
ndx = ndx + M(:, 7) * offsets(6);
Z2=[];
Z2(ndx) = X;
Z2 = reshape(Z2, [siz]);
在更新的时间测试中使用它我得到:
Elapsed time is 43.754363 seconds.
Elapsed time is 1.045980 seconds.
Elapsed time is 0.689487 seconds.
所以,仍然比循环更好,但看起来在这个多维案例中,accumarray(Rafael的回答)获胜。我会考虑给他“接受的答案”。
答案 2 :(得分:0)
谢谢@ rafael-monteiro&amp; @SCFRench。
我原来的程序更快。我在下面粘贴了一个基准测试脚本。
M=[1 0; 0 0; 1 1; 0 1];
X = [0.3 0.4 0.5 0.2];
nrep=50000;
%% My own code
tic
for A=1:nrep;
MN=M+1; % I know I can do this outside of the loop, but comparison with this seems more fair.
Z=zeros(size(X,2)/2,size(X,2)/2); % without pre-allocation it is twice as fast, I guess finding the size and the computation does not help here!
for I=1:4
Z1(MN(I,1),MN(I,2))=X(I);
end
end
toc
%% SCFrench code
tic
for A=1:nrep;
Z2(sub2ind([2 2], M(:, 1) + 1, M(:, 2) + 1)) = X;
Z2 = reshape(Z2, 2, 2);
end
toc
%% Rafael code
tic
for A=1:nrep;
Z3 = accumarray(M + 1, X, [2 2]);
end
toc
Elapsed time is 0.115488 seconds. % mine
Elapsed time is 1.082505 seconds. % SCFrench
Elapsed time is 0.282693 seconds. % rafael
编辑:
使用更大的数据,第一个实现似乎要慢得多。
alts=7;
M = dec2bin(0:2^alts-1)-'0';
X = rand(size(M,1),1);
nrep=50000;
tic
for A=1:nrep;
MN=M+1;
for I=1:128
Z1(MN(I,1),MN(I,2),MN(I,3),MN(I,4),MN(I,5),MN(I,6),MN(I,7))=X(I);
end
end
toc
tic
for A=1:nrep;
Z2(sub2ind([2 2 2 2 2 2 2], M(:, 1) + 1, M(:, 2) + 1, M(:, 3) + 1, M(:, 4) + 1, M(:, 5) + 1, M(:, 6) + 1, M(:, 7) + 1)) = X;
Z2 = reshape(Z2, [2 2 2 2 2 2 2]);
end
toc
tic
for A=1:nrep;
Z3 = accumarray(M + 1, X, [2 2 2 2 2 2 2]);
end
toc
Elapsed time is 33.390247 seconds. % Mine
Elapsed time is 4.280668 seconds. % SCFrench
Elapsed time is 0.629584 seconds. % Rafael