Как лучше всего построить матрицу, элементы которой являются в точности их индексами в Matlab?


РЕДАКТИРОВАТЬ: существующие ответы на этот вопрос применимы к тому, как построить матрицу, элементы которой являются функциями своих индексов. Я добавил это к заголовку вопроса.


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

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

Размер матриц для моих приложений имеет тенденцию быть большим (размер сотен в квадрате как минимум). В результате методы, использующие собственные функции Matlab, вероятно, намного лучше, чем циклы for / while.

Например, для матрицы размера [2 2] я хотел бы сделать либо

IND = 
[1 1]  [1 2]
[2 1]  [2 2]

Или

X = 
1 1
2 2
Y =
1 2
1 2

В конце я надеюсь сделать что-нибудь вроде

matrixIneed = arrayfun(@(s)..., IND)

Где s - вектор размера 2, или

matrixIneed = arrayfun(@(i,j)..., X,Y)

Последнее является предпочтительным.


РЕДАКТИРОВАТЬ: примечание о принятом ответе.

Я принял ответ Эндрю, потому что он мне интуитивно понятен, а код кажется быстрым (по крайней мере, мне).

Если вы когда-нибудь ответите на этот вопрос в Google, вы, вероятно, будете беспокоиться о производительности, как и я. (В противном случае, если бы не лучшая практика, любой может придумать двойной цикл для выполнения задачи.)

Если это так, вам предлагается изучить комментарий Эндрю о функции reshape() и ответ Роди о производительности meshgrid() и loops.

Тем не менее, решение thewaywewalk с meshgrid() является полезным примером для изучения функции meshgrid(). И это полезно во многих других функциях Matlab.

Решение Jigg repmat() также может вам помочь.

6
Argyll 17 Мар 2014 в 19:45

5 ответов

Лучший ответ

Взгляните на функции ind2sub, sub2ind и reshape. Они полезны для преобразования индексов и индексов многомерных массивов.

В вашем случае похоже, что вы этого хотите. (Я думаю, вам нужны «индексы» вместо «индексов». Matlab использует «индекс» для обозначения «линейного» индекса элемента при просмотре массива как одномерного вектора, а «индексы» - для обозначения позиции вдоль каждого измерение многомерного массива.)

sz = [3 3];  % Size of your matrix
n = prod(sz); % Total number of elements in matrix
[X, Y] = ind2sub(sz, 1:n);  % Subscripts, returned as vectors
X = reshape(X, sz);  % Reshape the subscript vectors to match your matrix
Y = reshape(Y, sz);

Подход meshgrid, который дал @thewaywewalk, даст тот же результат, но я думаю, что подход ind2sub в этом случае немного более читабелен, поскольку он сформулирован в терминах индексации массива, что является вашей проблемной областью . И он будет обобщен для работы с срезами или произвольными подмножествами массивов, чего не будет meshgrid, и хорошо соответствует ind2sub для эффективных операций, идущих в обратном направлении. (В любом случае стоит изучить meshgrid; он появляется в других местах.)

3
Andrew Janke 17 Мар 2014 в 21:36

Поскольку вы указали, что хотите запустить функцию для индексов, это, безусловно, самый простой и, вероятно, самый быстрый способ просто создать двойной цикл:

matrixIneed = zeros(n,m);
for ii = 1:n
    for jj = 1:m
        matrixIneed(ii,jj) = myFunction(ii,jj);
    end
end

В некоторой степени в зависимости от myFunction, это, вероятно, будет быстрее, чем arrayfun, и, конечно же, потребует гораздо меньше памяти, чем meshgrid, когда n или m относительно большой; см. также этот связанный вопрос .

Если вы используете MATLAB R2009 или новее, и ваша функция является встроенной или может быть построена с использованием только встроенных модулей, время выполнения этих циклов по сравнению с meshgrid будет сопоставимым, но {{X1} } будет потреблять гораздо больше памяти (O (N²) памяти в отличие от O (1) для цикла). Как всегда, профилирование является ключевым моментом, но двойной контур, вероятно, является лучшим универсальным решением.

Иногда это также помогает:

matrixIneed = zeros(n*m,1);
for ij = 1:n*m

    %// use this when possible
    matrixIneed(ij) = myFunction(ij); 

    %// otherwise, use this
    matrixIneed(ij) = myFunction(mod(ij-1,n)+1, floor((ij-1)/n)+1);  
end
reshape(matrixIneed,n,m);
1
Community 23 Май 2017 в 14:56

Привыкайте к ndgrid. Избегайте meshgrid, за исключением поддержки черчения и графических операций. .

Выходные данные ndgrid, выраженные в терминах строк, столбцов и т. Д., Имеют более естественную семенатику для матричных операций MATLAB, чем координаты x, y, возвращаемые meshgrid.

>> nrows = 3;
>> ncols = 4;
>> [II,JJ] = ndgrid(1:nrows,1:ncols)
II =
     1     1     1     1
     2     2     2     2
     3     3     3     3
JJ =
     1     2     3     4
     1     2     3     4
     1     2     3     4

Порядок измерений в MATLAB - это строки как первое измерение, столбцы как второе, затем более высокие измерения. ndgrid следует этому соглашению при упорядочении входов и выходов. Для справки: эквивалентной командой meshgrid является [JJ,II] = meshgrid(1:ncols,1:nrows);.

Отличная иллюстрация того, почему вы должны придерживаться строк и столбцов, - это преобразование в линейные индексы: sub2ind. Функция sub2ind ожидает индексы, упорядоченные так же, как выходные данные ndgrid:

>> inds = sub2ind([nrows ncols],II,JJ)
inds =
     1     4     7    10
     2     5     8    11
     3     6     9    12

Формулировка этой команды не требует особых размышлений, если вы всегда думаете в терминах строк, столбцов (индексов), а не x, y.

Снова используйте ndgrid.

4
chappjc 17 Мар 2014 в 22:01

Другой вариант с использованием repmat (поскольку содержимое этих матриц избыточно):

X=repmat((1:size(YourMatrix, 2))', 1, size(YourMatrix, 1));
Y=repmat(1:size(YourMatrix, 1), size(YourMatrix, 2), 1);
0
Cape Code 17 Мар 2014 в 22:25

Используйте meshgrid или ndgrid:

% example matrix
Matrix = magic(5)

[n m] = size(Matrix)
% or define the dimensions directly
n = 5;
m = 5;

[X,Y] = meshgrid(1:n,1:m)     %\\ [Y,X] = ndgrid(1:n,1:m) 

(различие для вашего 2D-случая состоит в том, что Y и X меняются местами. - Используйте это в соответствии с вашими потребностями.)

Из документации :

[X,Y] = meshgrid(xgv,ygv) копирует векторы сетки xgv и ygv, чтобы произвести полную сетку. Эта сетка представлена ​​выходной координатой массивы X и Y. Выходные массивы координат X и Y содержат копии векторов сетки xgv и ygv соответственно. Размеры выходные массивы определяются длиной векторов сетки. Для векторы сетки xgv и ygv длины M и N соответственно, X и Y будут иметь N строк и M столбцов.

Что ж, здесь нечего объяснять, meshgrid используется для создания регулярной сетки из двух векторов, обычно значений "x" и "y", чтобы получить подходящие входные данные для трехмерный / цветной график z - данных. Если вы предположите, что ваши x и y являются векторами [1 2 3 ... n], он сделает именно то, что вам нужно.

Возвращает :

X =

     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5


Y =

     1     1     1     1     1
     2     2     2     2     2
     3     3     3     3     3
     4     4     4     4     4
     5     5     5     5     5
7
Robert Seifert 17 Мар 2014 в 19:55