разделить длинную 2D-матрицу на третье измерение

Скажем, у меня есть следующая матрица:

A = randi(10, [6 3])
     7    10     3
     5     5     7
    10     5     1
     6     5    10
     4     9     1
     4    10     1

И я хотел бы извлечь каждые 2 строки и поместить их в третье измерение, чтобы результат был таким:

B(:,:,1) =
     7    10     3
     5     5     7
B(:,:,2) =
    10     5     1
     6     5    10
B(:,:,3) =
     4     9     1
     4    10     1

Я, очевидно, могу сделать это с помощью цикла for, просто интересно, как сделать это более элегантно, как однострочный, используя permute/reshape/.. (обратите внимание на размер матрицы и шаг быть параметрами)

% params
step = 5;
r = 15;
c = 3;

% data
A = randi(10, [r c]);
B = zeros(step, c, r/step); % assuming step evenly divides r

% fill
counter = 1;
for i=1:step:r
    B(:,:,counter) = A(i:i+step-1, :);
    counter = counter + 1;
end

person Amro    schedule 07.09.2009    source источник


Ответы (2)


Вот однострочное решение с использованием reshape и permute:

C = 3;          % Number of columns
R = 6;          % Number of rows
newR = 2;       % New number of rows
A = randi(10, [R C]);  % 6-by-3 array of random integers
B = permute(reshape(A.', [C newR R/newR]), [2 1 3]);

Это, конечно, требует, чтобы newR равномерно делилось на R.

person gnovice    schedule 07.09.2009
comment
Именно то, что мне было нужно, спасибо! Кстати, как вы можете индексировать матрицу по строкам, а не по столбцам (как это делает MATLAB)? - person Amro; 08.09.2009
comment
Линейная индексация матричных элементов MATLAB всегда следует порядку столбцов. Если вы хотите получить доступ к элементам вдоль строк, вы должны сначала транспонировать матрицу, прежде чем выполнять линейную индексацию. Вот почему у меня есть A' в качестве первого аргумента RESHAPE в приведенном выше решении. Для получения дополнительной информации об индексации матриц в MATLAB перейдите по этой ссылке: mathworks.com /company/newsletters/digest/sept01/matrix.html - person gnovice; 08.09.2009

Вот однострочник с reshape и permute, но без переноса входного массива -

out = permute(reshape(A,newR,size(A,1)/newR,[]),[1 3 2]);

, где newR — количество строк в выходном массиве 3D.


Бенчмаркинг

В этом разделе предложенный в этом сообщении подход сравнивается с other solution with reshape, permute & transpose по производительности. Размеры данных завышены пропорционально тем, которые перечислены в вопросе. Таким образом, A имеет размер 60000 x 300, и мы разделим его таким образом, чтобы на выходе 3D было 200 rows и, таким образом, в dim-3 было бы 300 записей.

Сравнительный код -

%// Input
A = randi(10, [60000 300]); %// 2D matrix
newR = 200;                 %// New number of rows

%// Warm up tic/toc.
for k = 1:50000
    tic(); elapsed = toc();
end

N_iter = 5; %// Number of iterations for each approach to run with

disp('---------------------- With PERMUTE, RESHAPE & TRANSPOSE')
tic
for iter = 1:N_iter
    [R,C] = size(A);
    B = permute(reshape(A',[C newR R/newR]),[2 1 3]); %//'
end
toc, clear B R C iter

disp('---------------------- With PERMUTE & RESHAPE')
tic
for iter = 1:N_iter
    out = permute(reshape(A,newR,size(A,1)/newR,[]),[1 3 2]);
end
toc

Выход -

---------------------- With PERMUTE, RESHAPE & TRANSPOSE
Elapsed time is 2.236350 seconds.
---------------------- With PERMUTE & RESHAPE
Elapsed time is 1.049184 seconds.
person Divakar    schedule 01.01.2016