如何避免在3D数组中从多个页面访问不同的行,同时避免for
-loop?
假设我有一个10x5x3
矩阵(mat1
),我想将三个页面(例如第一,第二和第三页的第四,第二和第五行)中不同的单独行复制到另一个10x5x3
矩阵的第一行(mat2
)。
我的解决方案使用for
-loop。矢量化呢?
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
gnovice.. 5
任何矢量化解决方案都不会像for循环解决方案那样简单,并且实际上效率可能更低(编辑:请参见下面的时序测试)。但是,如果您好奇,对这样的索引操作进行向量化通常会涉及将所需的索引从下标转换为线性索引。通常,您可以使用来执行此操作sub2ind
,但是由于您要选择整行,因此自己计算索引可能会更有效。
这是一个在较新版本的MATLAB(R2016b及更高版本)中利用隐式扩展的解决方案:
[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
。以下是结果,显示了循环时间与索引时间的比率:
除了一些瞬态噪声外,还有一些清晰的图案。增加行数或列数(蓝线或红线)不会明显改变时间比例,时间比例徘徊在0.7到0.9之间,这意味着for循环的平均速度略快。增加页面数(黄线)意味着for循环必须迭代更多次,并且索引解决方案迅速开始获胜,当页面大小超过约150时达到8倍加速。
任何矢量化解决方案都不会像for循环解决方案那样简单,并且实际上效率可能更低(编辑:请参见下面的时序测试)。但是,如果您好奇,对这样的索引操作进行向量化通常会涉及将所需的索引从下标转换为线性索引。通常,您可以使用来执行此操作sub2ind
,但是由于您要选择整行,因此自己计算索引可能会更有效。
这是一个在较新版本的MATLAB(R2016b及更高版本)中利用隐式扩展的解决方案:
[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
。以下是结果,显示了循环时间与索引时间的比率:
除了一些瞬态噪声外,还有一些清晰的图案。增加行数或列数(蓝线或红线)不会明显改变时间比例,时间比例徘徊在0.7到0.9之间,这意味着for循环的平均速度略快。增加页面数(黄线)意味着for循环必须迭代更多次,并且索引解决方案迅速开始获胜,当页面大小超过约150时达到8倍加速。