【问题标题】:Vectorizing the assignment of values into a 3D array将值的分配向量化为 3D 数组
【发布时间】:2015-12-06 17:44:59
【问题描述】:

下面是简单的代码:

A=zeros(60,60,30);
a=rand(28,28,30);

for i=1:30
    m=round(rand*32)+1; %because 60-28=32
    n=round(rand*32)+1;
    A(m:m+27,n:n+27,i)=a(:,:,i);
end

它所做的只是取一个 28*28 的随机矩阵并将其“植入”到一个更大的(零)矩阵中,然后重复 30 次。每次,它随机选择一个不同的角位置(即'm'和'n')将小矩阵放置在大矩阵中。 我确信我可以在没有 for 循环的情况下做到这一点 - 只是不确定如何。

【问题讨论】:

  • 我认为你不能避免循环并在这里只使用索引。您需要自己的循环或像 arrayfun 这样的函数。
  • "Without for" 和 "vectorization" 不一定是同一回事。您是在寻找一个单行代码,还是一个不调用任何后续函数来屏蔽 for 循环的单行代码?

标签: matlab multidimensional-array vectorization bsxfun


【解决方案1】:

这里的所有技巧都是关于 MATLAB 中使用的线性索引。我们创建偏移线性索引时牢记最终输出的大小。首先,将创建偏移索引以索引到A 的一个 3D 切片,然后索引到整个 3D 数组。它们在代码中分别命名为offset2Doffset3D。最后,我们添加从mn 获得的线性索引。

假设您将mn 索引保存到两个单独的一维数组中,例如m_arrn_arr,您将获得带有bsxfun 的最终矢量化实现,就像这样 -

%// Say you have the m,n arrays are created like this -
m_arr = round(rand(30,1)*32)+1;
n_arr = round(rand(30,1)*32)+1;

%// Get linear indices with m,n
mn_arr = (n_arr-1)*size(A,1) + m_arr;

%// Calculate offset indices for 2D and then 3D versions
offset2D = bsxfun(@plus,[0:27]',[0:27]*size(A,1));  %//'
offset3D = bsxfun(@plus,offset2D(:),[0:30-1]*numel(A(:,:,1)));

%// Incorporate m,n indices into offset to get final linear indices to index into A
lidx = bsxfun(@plus,mn_arr(:).',offset3D);  %//'

%// Initialize output array and then index into A to values from a
A = zeros(60,60,30);
A(lidx) = a;

对于未来的读者,这里是 for 循环和矢量化代码的参数化版本 -

%// Parameters
M = 4;
D = 3;
mx = 3;

%// For-loop code
A = zeros(M+mx,M+mx,D);
a = rand(M,M,D);
m_arr = round(rand(D,1)*mx)+1;
n_arr = round(rand(D,1)*mx)+1;
for i=1:D
    m = m_arr(i);
    n = n_arr(i);
    A(m:m+M-1,n:n+M-1,i) = a(:,:,i);
end

%// Vectorized code
mn_arr = (n_arr-1)*size(A,1) + m_arr;
offset2D = bsxfun(@plus,[0:M-1]',[0:M-1]*size(A,1));  %//'
offset3D = bsxfun(@plus,offset2D(:),[0:D-1]*numel(A(:,:,1)));
lidx = bsxfun(@plus,mn_arr(:).',offset3D);  %//'
A_vectorized = zeros(M+mx,M+mx,D);
A_vectorized(lidx) = a;

最后,让我们比较一下循环代码和矢量化代码的输出 -

>> max(abs(A(:)-A_vectorized(:)))
ans =
     0

【讨论】:

  • 非常好!并且代码很容易用 cmets 来理解
  • @LuisMendo 我很烂,我在 cmets 上尽力了 :)
  • 这里也一样。 Rayryeng 是解释代码的真正大师 :-) 假设我们让代码自己说话 :-P
  • @LuisMendo 没错!我喜欢 OP comeon 阅读代码,它们很容易理解;)不,我想解释一下只是懒惰 :)
  • @LuisMendo - 哈哈哈谢谢 :) 顺便说一句,为你 Divakar +1。解释得很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 2017-02-14
  • 2019-09-25
  • 2017-03-16
  • 1970-01-01
相关资源
最近更新 更多