从3D数组中的多个页面访问不同的行

时间:2019-07-03 13:01:41

标签: matlab multidimensional-array vectorization

如何在避免for循环的同时访问3D数组中多个页面的不同行?

让我们假设我有一个10x5x3矩阵(mat1),并且我想从三个页面(例如第一,第二个第四,第二和第五行)中复制不同的单独行和第3页)插入另一个10x5x3矩阵(mat2)的第一行。

我的解决方案使用for循环。向量化呢?

mat1 = randi(100, 10, 5, 3)
mat2 = nan(size(mat1))

rows_to_copy = [4, 2, 5]

for i = 1 : 3
    mat2(1, :, i) = mat1(rows_to_copy(i), :, i)
end

1 个答案:

答案 0 :(得分:5)

任何矢量化解决方案都不会像for循环解决方案那样简单,并且可能实际上效率较低( 编辑: 参见下面的计时测试)。但是,如果您好奇,对这样的索引操作进行向量化通常会涉及将所需的索引从下标转换为linear indices。通常,您可以使用sub2ind进行此操作,但是由于您要选择整行,因此自己计算索引可能会更有效。

以下是在较新版本的MATLAB(R2016b及更高版本)中利用implicit expansion的解决方案:

[R, C, D] = size(mat1);
index = rows_to_copy+R.*(0:(C-1)).'+R*C.*(0:(D-1));
mat2(1, :, :) = reshape(mat1(index), 1, C, D);

请注意,如果您实际上并不需要NaN中的mat2值所充满的所有多余空间,则可以通过将所有行串联到二维矩阵中来使结果更紧凑代替:

>> mat2 = mat1(index).'

mat2 =

    95    41     2    19    44
    38    31    93    27    27
    49    10    72    91    49

如果您仍在使用旧版本的MATLAB而没有进行隐式扩展,则可以改用bsxfun

index = bsxfun(@plus, rows_to_copy+R*C.*(0:(D-1)), R.*(0:(C-1)).');


计时

我使用timeit(R2018a,Windows 7 64位)运行了一些测试,以了解比较循环和索引解决方案的方式。我测试了3种不同的情况:mat1的行大小,列大小和页面大小(第三维)的增加。 rows_to_copy是随机选择的,并且元素的数量始终与mat1的页面大小相同。以下是结果,显示了循环时间与索引时间的比率:

enter image description here

除了一些瞬态噪声外,还有一些清晰的图案。增加行数或列数(蓝线或红线)不会明显改变时间比例,时间比例徘徊在0.7到0.9之间,这意味着for循环的平均速度略快。增加页面数(黄线)意味着for循环必须迭代更多次,并且索引解决方案迅速开始胜出,当页面大小超过150左右时,索引解决方案将达到8倍加速。