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

Access different rows from multiple pages in 3D array

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

假设我有一个 10x5x3 矩阵 (mat1),我想从三页中复制不同的行(例如第一页的第 4、2 和 5 行) 、第 2 和第 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

任何矢量化解决方案都可能不会像您的 for 循环解决方案那么简单,并且可能实际上效率较低(编辑: 请参阅下面的时序测试)。但是,如果您很好奇,像这样向量化索引操作通常涉及将所需的索引从下标转换为 linear indices. Normally you can do this using 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);

请注意,如果您真的不需要 mat2 中充满 NaN 值的所有额外 space,您可以通过连接所有行来使结果更紧凑改为二维矩阵:

>> 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 是 运行domly 选择的,并且始终具有与 mat1 的页面大小相同的元素数。以下是结果,显示了循环时间与索引时间的比率:

除了一些 t运行sient 噪声,还有一些清晰的模式。增加行数或列数(蓝线或红线)不会明显改变时间比率,时间比率徘徊在 运行ge 的 0.7 到 0.9 之间,这意味着 for 循环平均略快一些。增加页面数量(黄线)意味着 for 循环必须迭代更多次,索引解决方案很快开始胜出,当页面大小超过 150 时达到 8 倍加速。