Warm tip: This article is reproduced from stackoverflow.com, please click
matlab multidimensional-array vectorization

Access different rows from multiple pages in 3D array

发布于 2020-03-27 10:22:04

How can I access different rows from multiple pages in a 3D array while avoiding a for-loop?

Let's assume I have a 10x5x3 matrix (mat1) and I would like to copy different individual rows from the three pages (such as the 4th, 2nd, and 5th row of the 1st, 2nd, and 3rd page) into the first row of another 10x5x3 matrix (mat2).

My solution uses a for-loop. What about vectorization?

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
Questioner
Andi
Viewed
58
gnovice 2019-07-03 23:34

Any vectorized solution is likely not going to be as simple as your for loop solution, and might actually be less efficient (edit: see timing tests below). However, if you're curious, vectorizing an indexing operation like this generally involves converting your desired indices from subscripts to linear indices. Normally you can do this using sub2ind, but since you're selecting entire rows it may be more efficient to calculate the index yourself.

Here's a solution that takes advantage of implicit expansion in newer versions of MATLAB (R2016b and later):

[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);

Note that if you don't really need all the extra space full of NaN values in mat2, you can make your result more compact by just concatenating all the rows into a 2-D matrix instead:

>> mat2 = mat1(index).'

mat2 =

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

And if you're still using an older version of MATLAB without implicit expansion, you can use bsxfun instead:

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


Timing

I ran some tests using timeit (R2018a, Windows 7 64-bit) to see how the loop and indexing solutions compared. I tested 3 different scenarios: increasing row size, increasing column size, and increasing page size (third dimension) for mat1. The rows_to_copy was randomly selected and always had the same number of elements as the page size of mat1. Here are the results, showing the ratio of the loop time versus the indexing time:

enter image description here

Aside from some transient noise, there are some clear patterns. Increasing either the number of rows or columns (blue or red lines) doesn't appreciably change the time ratio, which hovers in the range of 0.7 to 0.9, meaning the for loop is slightly faster on average. Increasing the number of pages (yellow line) means the for loop has to iterate more times, and the indexing solution quickly starts to win out, reaching an 8 times speedup when the page size exceeds about 150.