Линейный индекс максимума многомерной матрицы

Допустим, у меня есть матрица 3-dimensional, я вычислил max по второму измерению и хочу получить линейные индексы максимальных значений. Однако max-function возвращает индексы только по одному измерению.

A = randn([5,5,5]);        % Generate random matrix
[M, Ind] = max(A,[],2);    % Take the max along dimension 2

Как передать index в linear indexing, чтобы

M == A(Ind)

становится правдой?

Мое намерение для этой проблемы состоит в том, что у меня есть матрицы two multi-dimensional и мне нужно вычислить max в first. Затем я хочу получить доступ к значениям в матрице second именно в тех позициях, где я нашел максимум в first.


person dast    schedule 29.10.2014    source источник
comment
Если вам небезразлична производительность, вот быстрый тест решений, опубликованных здесь: ideone.com/cOV5D3.   -  person Divakar    schedule 30.10.2014


Ответы (4)


Один из способов — использовать sub2ind:

A = randn([5,5,5]);       
[M, col] = max(A,[],2);   

[m,n,o] = size(A);

dim1 = mod((0:m*o-1)', m)+1;
dim2 = col(:);
dim3 = ceil((1:m*o)/m)';

ind = sub2ind(size(A), dim1, dim2, dim3)

убедитесь, что он работает с

isequal(M(:), A(ind))

чтобы они имели ту же форму, что и M:

reshape(ind, m, 1, o)
person Dan    schedule 29.10.2014
comment
Отличный комментарий, с вашей помощью я смог справиться с проблемой. У меня были проблемы с пониманием параметров sub2ind. Однако я мог бы распространить это решение даже на пять измерений в матрице A. - person dast; 30.10.2014
comment
Нет проблем :) Не забудьте принять один из этих ответов. хоть... - person Dan; 30.10.2014

Создайте индексы для других измерений.

В dim 1 индекс должен измениться быстрее всего: [1,2,...,size(A,1)] и это size(A,3) раз:

idx1 = repmat((1:size(A,1))',size(A,3),1);

В dim 2 индекс задается как Ind.

В dim 3 индекс должен изменяться медленнее всего: [1,1,...,1] в течение size(A,1) раз, а затем [2,2,...,2] и так далее до size(A,3).

idx3 = ones(size(A,1),1)*(1:size(A,3));

Доступ к отдельным значениям:

 M_ = A(sub2ind(size(A),idx1(:),Ind(:),idx3(:)));

Сравнивать:

M(:) == M_
person Steffen    schedule 29.10.2014
comment
Это решение очень похоже на решение Дэна, спасибо за объяснение формы параметра (idx1, idx3,...) - person dast; 30.10.2014

Трехмерный случай:

[m, n, p] = size(A);
[M, Ind] = max(A,[],2);
LinInd = bsxfun(@plus, (1:m).', (0:p-1)*m*n); %'//
LinInd = LinInd(:) + (Ind(:)-1)*m;

Желаемый линейный индекс LinInd. Это производит

A(LinInd) == M(:)

со всеми true записями (обратите внимание, что вам нужно (:) справа, чтобы сравнение имело смысл).

Общий многомерный случай:

d = 3; %// dimension along which max will be computed
s = size(A);
sLow = prod(s(1:d-1));
sHigh = prod(s(d+1:end));
[M, Ind] = max(A,[],d);
LinInd = bsxfun(@plus, (1:sLow).', (0:sHigh-1)*sLow*s(d)); %'//
LinInd = LinInd(:) + (Ind(:)-1)*sLow;
person Luis Mendo    schedule 29.10.2014
comment
Довольно короткое решение. Однако может быть сложно распространить на несколько измерений. Я не указал это в наборе задач, но тем не менее, постарайтесь решать задачи в общем виде. Спасибо. - person dast; 30.10.2014
comment
Многомерный случай отлично сработал для меня. Спасибо! - person gtownescapee; 18.02.2016
comment
@gtownescapee Отлично! - person Luis Mendo; 18.02.2016

Предположим, что у вас есть две матрицы A и B, и вам нужно получить индексы max из A и использовать эти индексы для индексации в B для получения желаемого результата. Один из подходов к достижению того же может быть таким:

%// Your code to get Ind
A = randn([5,5,5]);        % Generate random matrix
[M, Ind] = max(A,[],2);    % Take the max along dimension 2

%// ------- Solution code -------------

%// Get the size of A
[n1,n2,n3] = size(A)

%// Linear indices corresponding to column and third dimension indices
col_dim3_lin_idx = bsxfun(@plus,(Ind-1)*n1,permute([0:n3-1]*n1*n2,[1 3 2]))

%// Finally get the overall linear indices
linear_index = bsxfun(@plus,col_dim3_lin_idx,[1:n1]') %//'

%// Get the corresponding elements from B
out = B(linear_index)

Немного другой способ получить желаемые линейные индексы в виде двумерного массива будет таким:

[n1,n2,n3] = size(A) %// Get the size of A
idx = bsxfun(@plus,bsxfun(@plus,squeeze((Ind-1)*n1),[0:n3-1]*n1*n2),[1:n1]')

idx(:) будет вектором-столбцом линейных индексов с этим новым подходом, который вы можете индексировать в B, т.е. B(idx(:)), чтобы получить желаемый результат в виде вектора-столбца.

person Divakar    schedule 29.10.2014
comment
Однако спасибо за ответ, я думаю, что решение с sub2ind может быть быстрее, поскольку ваши коды требуют операций и перестановок bsxfun, которые могут замедлить код. Тем не менее, я не оценил его. - person dast; 30.10.2014
comment
@dast Я думаю, вам следует попробовать все эти решения и убедиться в сравнении времени выполнения. Кроме того, позвольте мне спросить вас - какой должен быть выходной формат для линейных индексов? Вы хотите иметь вектор-столбец индексов или сохранить его тех же размеров, что и Ind, который представляет собой массив N x 1 x M. - person Divakar; 30.10.2014
comment
Да, линейные индексы должны быть вектор-столбцом. Массив N x 1 x M — это то, что возвращает функция max. - person dast; 01.11.2014
comment
@dast Поскольку вы спрашивали о производительности во время выполнения, вы можете проверить их здесь — ideone.com/cOV5D3 - person Divakar; 01.11.2014