Доступ к различным строкам с нескольких страниц в 3D-массиве - PullRequest
2 голосов
/ 03 июля 2019

Как я могу получить доступ к различным строкам с нескольких страниц в трехмерном массиве, избегая при этом for -циклов?

Предположим, у меня есть матрица 10x5x3 (mat1), и я хотел быскопируйте разные отдельные строки с трех страниц (например, 4-й, 2-й и 5-й строки 1-й, 2-й и 3-й страницы) в первый ряд другой 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

1 Ответ

5 голосов
/ 03 июля 2019

Любое векторизованное решение, вероятно, не будет таким простым, как ваше решение для цикла, и может на самом деле менее эффективно ( edit: см. Тесты синхронизации ниже ).Однако, если вам интересно, векторизация операции индексирования, подобная этой, обычно включает преобразование желаемых индексов из индексов в линейные индексы .Обычно вы можете сделать это, используя 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.Вот результаты, показывающие соотношение времени цикла и времени индексации:

enter image description here

Помимо некоторых переходных шумов, существуют некоторые четкие закономерности.Увеличение числа строк или столбцов (синие или красные линии) существенно не меняет соотношение времени, которое колеблется в диапазоне от 0,7 до 0,9, что означает, что цикл for в среднем немного быстрее.Увеличение количества страниц (желтая линия) означает, что цикл for должен повторяться больше раз, и решение для индексирования быстро начинает выигрывать, достигая 8-кратного ускорения, когда размер страницы превышает 150.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...