Компактная матричная индексация MATLAB - PullRequest
8 голосов
/ 27 апреля 2009

У меня есть матрица размером n на k, содержащая k чисел в строке. Я хочу использовать эти k чисел в качестве индексов в k-мерной матрице. Есть ли какой-нибудь компактный способ сделать это в MATLAB или я должен использовать цикл for?

Это то, что я хочу сделать (в псевдокоде MATLAB), но более в MATLAB-стиле:

for row=1:1:n
    finalTable(row) = kDimensionalMatrix(indexmatrix(row, 1),...
          indexmatrix(row, 2),...,indexmatrix(row, k))
end

Ответы [ 3 ]

15 голосов
/ 27 апреля 2009

Если вы хотите избежать использования цикла for, это, вероятно, самый чистый способ сделать это:

indexCell = num2cell(indexmatrix, 1);
linearIndexMatrix = sub2ind(size(kDimensionalMatrix), indexCell{:});
finalTable = kDimensionalMatrix(linearIndexMatrix);

Первая строка помещает каждый столбец indexmatrix в отдельные ячейки массива ячеек, используя num2cell. Это позволяет нам передавать все k столбцы как список через запятую в sub2ind, функцию, которая преобразует индексы с индексами (строка, столбец и т.д.) в линейные индексы (каждый матричный элемент пронумерован от 1 до N, N - общее количество элементов в матрице). Последняя строка использует эти линейные индексы для замены вашего цикла for. Хорошее обсуждение матричной индексации (подстрочное, линейное и логическое) можно найти здесь .

Еще немного пищи для размышлений ...

Тенденция уклоняться от циклов for в пользу векторизованных решений - это то, к чему привыкли многие пользователи MATLAB (включая меня). Тем не менее, новые версии MATLAB обрабатывают циклы гораздо эффективнее. Как обсуждалось в , этот ответ на другой вопрос SO, использование циклов for может иногда приводить к более быстрому выполнению кода, чем если бы вы использовали векторизованное решение.

Я, конечно, НЕ говорю, что вы не должны пытаться векторизовать свой код больше, только то, что каждая проблема уникальна. Векторизация часто будет более эффективной, но не всегда . Для вашей проблемы скорость выполнения циклов for и векторизованного кода, вероятно, будет зависеть от того, насколько велики значения n и k.

6 голосов
/ 27 апреля 2009

Чтобы рассматривать элементы вектора indexmatrix(row, :) как отдельные индексы, эти элементы необходимы как массив ячеек. Итак, вы можете сделать что-то вроде этого

subsCell = num2cell( indexmatrix( row, : ) );
finalTable( row ) = kDimensionalMatrix( subsCell{:} );

Чтобы развернуть subsCell как список, разделенный запятыми, к сожалению, вам нужны две отдельные строки. Однако этот код не зависит от k.

0 голосов
/ 05 декабря 2012

Преобразуйте ваши субиндексы в линейные индексы хакерским способом

ksz = size(kDimensionalMatrix);
cksz = cumprod([ 1 ksz(1:end-1)] );
lidx = ( indexmatrix - 1 ) * cksz' + 1; #'
% lindx is now (n)x1 linear indices into kDimensionalMatrix, one index per row of indexmatrix
% access all n values:
selectedValues = kDimensionalMatrix( lindx );

Ура! * * 1004

...