Линейная индексация, логическая индексация и все такое

31

Мы используем различные формы индексирования в Matlab:

  • стандарт (используя целые числа вдоль каждого измерения),
  • логический (с использованием логических значений),
  • linear (используя один индекс для перемещения массива с более чем одним измерением).

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

>> A = magic(3)
A =
     8     1     6
     3     5     7
     4     9     2
>> A(A>5)
ans =
     8
     9
     6
     7

Это логическое индексирование, правильно? Но он также имеет некоторые особенности линейной индексации, потому что возвращается вектор столбца. Фактически, логический индекс A>5 имеет тот же эффект, что и линейный индекс find(A>5).

В качестве второго примера рассмотрим

>> A = magic(3)
A =
     8     1     6
     3     5     7
     4     9     2
>> A(1:2, [true false true])
ans =
     8     6
     3     7

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

Эти примеры (и более сложные, которые возникают на практике) задают следующие вопросы:

  • Какие типы индексирования существуют в Matlab?
  • Как их можно комбинировать?
  • Как их следует ссылаться?
Теги:
arrays
matrix
matrix-indexing

1 ответ

38
Лучший ответ

В дальнейшем я использую терминологию, которая, я думаю, более или менее соответствует стандартной практике Matlab. Однако в некоторых случаях мне приходилось сортировать имя, потому что я не знал о существующем. Пожалуйста, дайте мне знать, если есть более стандартные имена, чем те, которые я использую.

Этот ответ пытается прояснить различные типы индексирования и как их можно комбинировать. Другой вопрос заключается в том, как форма (size) выходного массива определяется как функция формы индексных переменных. Хорошей почтой на этом является Суть индексации Лорен Шуре.

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

Типы индексирования в числовых массивах

Индексация может быть классифицирована с учетом следующих двух атрибутов.

  1. Согласно числу измерений, к которым относится каждая индексная переменная, индексирование может быть многомерным или линейным. Но это всего лишь два крайних случая. Существует промежуточная ситуация, которую можно назвать частично линейной индексацией:

    • Чистая многомерная индексация задает индексную переменную для каждого измерения массива. Отдельные индексы иногда упоминаются как индексы в документации Matlab (см., Например, sub2ind).
    • Чистая линейная индексация задает единую индексную переменную, которая пересекает массив по всем измерениям (это можно рассматривать так, как если бы все размеры сворачивались в один). Как мы знаем, обход сначала по столбцам, затем по рядам, затем по трем-мерным срезам и т.д. (Так называемый порядок столбцов-майоров).
    • Частично линейное индексирование: заданный массив с m+n измерениями, n>=2, можно указать m индексных переменных для первых m измерений (таким образом, используя многомерную индексацию в этих измерениях) и одну индексную переменную для последних n измерений, которая равна интерпретируется как линейный индекс только для этих измерений (последние n измерений сворачиваются в один).
  2. В соответствии с типом значений индекса каждая индексная переменная может быть целочисленной или логической:

    • Он целочисленный, если индексная переменная содержит положительные целые числа;
    • Логично, если индексная переменная содержит логические значения.

Критерии классификации 1 и 2 являются независимыми. Категория индекса с точки зрения критерия 1 не имеет отношения к его категории в соответствии с критерием 2. Возможны все комбинации.

Таким образом, согласно вышеуказанной классификации, существует 6 основных типов индексирования. Чтобы прояснить, ниже приведен пример для каждого. Все примеры используют массив A = cat(3, magic(3), 9+magic(3)), то есть,

A(:,:,1) =
     8     1     6
     3     5     7
     4     9     2
A(:,:,2) =
    17    10    15
    12    14    16
    13    18    11
  1. Многомерный, целочисленный:

    >> A([1 2], 2, 2)
    ans =
        10
        14
    
  2. Линейный, целочисленный:

    >> A([2 5:7])
    ans =
         3     5     9     6
    
  3. Частично линейный, целочисленный:

    >> A([1 2], 2:4)
    ans =
         1     6    17
         5     7    12
    
  4. Многомерный, логический:

    >> A([true true false], [false true false], [false true])
    ans =
        10
        14
    

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

    >> A([true true], [false true false false], [false true])
    ans =
        10
        14
    

    Недопустимые значения интерпретируются как false, а избыточные значения должны быть false или произойдет ошибка. См., Например, эту страницу по Mathworks или этот ответ Джонаса.

  5. Линейный, логический:

    >> A([false true false false true true true])
    ans =
         3     5     9     6
    

    (Обратите внимание, что в векторе индексирования осталось 11 false значений).

  6. Частично линейный, логический:

    >> A([true true false], [false true true true false false])
    ans =
         1     6    17
         5     7    12
    

При многомерном или частично линейном индексировании, в котором имеется более одной индексной переменной, каждая из них может независимо быть целочисленной или логической. Это приводит к разным смешанным типам. Например:

  1. Многомерный, логический/целочисленный:

    >> A([true false true], [false true true], 2)
    ans =
        10    15
        18    11
    
  2. Частично линейный, целочисленный/логический:

    >> A([1 2], [true false true false true false])
    ans =
         8     6    10
         3     7    14
    

Если массив, который индексируется, является разреженной матрицей, все вышеприведенное все еще применяется, за исключением того, что для матриц не существует частично линейного индексации; и, конечно, результат также разрежен.

Индексирование массивов ячеек

Все типы индексирования, описанные для числовых массивов, могут быть применены к массивам ячеек с одним дополнительным рассмотрением. Ячейки могут быть проиндексированы скобками или фигурными фигурными скобками. В первом случае результатом индексации является массив ячеек. Во втором - список содержимого ячейки, разделенный запятыми.

В качестве примера предположим, что численный массив, используемый в предыдущих примерах, преобразуется в массив ячеек C = num2cell(A), то есть,

C(:,:,1) = 
    [8]    [1]    [6]
    [3]    [5]    [7]
    [4]    [9]    [2]
C(:,:,2) = 
    [17]    [10]    [15]
    [12]    [14]    [16]
    [13]    [18]    [11]

Тогда индексирование, используемое в примере 8 выше, даст массив ячеек

>> C([1 2], [true false true false true false])
ans = 
    [8]    [6]    [10]
    [3]    [7]    [14]

тогда как использование фигурных скобок даст список, разделенный запятыми

>> C{[1 2], [true false true false true false]}
ans =
     8
ans =
     3
ans =
     6
ans =
     7
ans =
    10
ans =
    14 

Выносное сообщение /TL; DR

Логическое и линейное индексирование не являются исключительными типами индексирования. Скорее, это две независимые функции индексирования. "Логический" относится к типу значений индекса, а "linear" означает, что несколько измерений свертываются и индексируются как единое целое. Обе функции могут выполняться одновременно.

  • 4
    Это заслуживает награды. Когда пост будет подходящим, я назначу вам один. Я также проголосовал за вопрос и ответ. Очень хорошая работа, Луис!
  • 0
    @rayryeng Спасибо за это! Но на самом деле я не говорю много нового. Я просто попытался привести в порядок свои идеи по индексации :-)
Показать ещё 9 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню