Трехмерная матрица: как использовать пары (строка, столбец) с подстановочным знаком 3-го измерения в MATLAB?

У меня есть трехмерная матрица и список пар (строка, столбец). Я хотел бы извлечь двумерную матрицу, которая соответствует элементам в этих позициях, спроецированных на глубину матрицы. Например, предположим,

>> a = rand(4, 3, 2)
a(:,:,1) =
    0.5234    0.7057    0.0282
    0.6173    0.2980    0.9041
    0.7337    0.9380    0.9639
    0.0591    0.8765    0.1693
a(:,:,2) =
    0.8803    0.2094    0.5841
    0.7151    0.9174    0.6203
    0.7914    0.7674    0.6194
    0.2009    0.2542    0.3600
>> rows = [1 4 2 1];
>> cols = [1 2 1 3];

Я хотел бы получить,

0.5234    0.8765    0.6173    0.0282
0.8803    0.2542    0.7151    0.5841

возможно с некоторой перестановкой размеров. Кроме того, хотя в этом примере подстановочный знак находится в последнем измерении, у меня также есть случаи, когда он находится в первом или втором измерении.

Я наивно попробовал a(rows, cols, :) и получил 3D-матрицу, где диагональная плоскость - это то, что я хочу. Я также нашел sub2ind, который будет извлекать нужные элементы из плоскости a(:,:,1). Я мог бы работать с одним из них, чтобы получить то, что я хочу, но мне интересно, есть ли более канонический, элегантный или эффективный метод, который мне не хватает?

Обновлять

Это было решение, которое я использовал, основываясь на ответе, опубликованном ниже,

sz = size(a);
subs = [repmat(rows, [1, sz(3)]);
     repmat(cols, [1, sz(3)]);
     repelem([1:sz(3)], length(rows))];
result = a(sub2ind(sz, subs(1,:), subs(2,:), subs(3,:)));

person john_stech    schedule 07.03.2017    source источник
comment
Если приведенный ниже ответ вам подходит, отметьте его как решение.   -  person Suever    schedule 09.03.2017


Ответы (1)


sub2ind - это в значительной степени то, что вам нужно использовать здесь для преобразования ваших индексов в линейные индексы (помимо ручного вычисления линейных индексов самостоятельно). Вы можете сделать что-то вроде следующего, который преобразует rows и cols в линейный индекс (в 2D-срезе), а затем добавляет смещение (равное количеству элементов в 2D-срезе) к этим индексам для выборки всех элементов в третье измерение.

sz = size(a);
inds = sub2ind(sz(1:2), rows, cols);
inds = bsxfun(@plus, inds, (0:(sz(3)-1)).' * prod(sz(1:2)));
result = a(inds);

И на самом деле вычислить линейные индексы самостоятельно

inds = (cols - 1) * sz(1) + rows;
inds = bsxfun(@plus, inds, (0:(sz(3) - 1)).' * prod(sz(1:2)));
result = a(inds);

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

% Create a new temporary matrix
anew = reshape(permute(a, [3, 1, 2]), size(a, 3), []);

% Grab all rows (the 3rd dimension) and compute the columns to grab
result = anew(:, (cols - 1) * size(a, 1) + rows);
person Suever    schedule 07.03.2017
comment
Я использовал этот подход с модификацией расчета inds, как показано в обновлении выше. - person john_stech; 15.03.2017