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

Мы привыкли к разным формам индексации в Matlab:

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

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

>> 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?
  • Как их совместить?
  • Как к ним относиться?

person Luis Mendo    schedule 03.09.2015    source источник


Ответы (1)


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

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

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

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

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

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

    • Pure multidimensional indexing specifies an index variable for each dimension of the array. The individual indices are sometimes referred to as subscripts in Matlab documentation (see for example sub2ind).
    • Чистая линейная индексация определяет одну индексную переменную, которая проходит по массиву по всем измерениям (это можно рассматривать так, как будто все измерения сворачиваются в одно). Как мы знаем, обход сначала выполняется по столбцам, затем по строкам, затем по третьим срезам и т. Д. (Так называемый порядок столбцов).
    • Частично линейное индексирование: для массива с m+n измерениями, n>=2 можно указать m индексные переменные для первых m измерений (таким образом, используя многомерное индексирование в этих измерениях) и одну индексную переменную для последних n измерений, который интерпретируется как линейный индекс только для этих измерений (последние n измерений объединяются в одно).
  2. В зависимости от типа значений индекса каждая переменная индекса может быть целочисленной или логической:

    • It is integer-valued if the index variable contains positive integers;
    • логично, если индексная переменная содержит логические значения.

Критерии классификации 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

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

person Luis Mendo    schedule 03.09.2015
comment
Сначала я подумал, что это будет дубликат этот вопрос / ответ. Это не так, но в любом случае это тесно связано. Я бы включил этот ответ, поскольку он объясняет все ошибки, связанные с неправильной индексацией. - person thewaywewalk; 03.09.2015
comment
@thewaywewalk Я не вижу, чтобы эти вопросы и ответы были связаны, не так ли? Этот имеет дело с ошибками, вызванными неправильными значениями индексов или функциями теневого копирования имен переменных. Это касается различных типов индексации, которые существуют в соответствии с двумя критериями; и пытается подчеркнуть, что эти два критерия независимы - person Luis Mendo; 03.09.2015
comment
Нашел вчера кое-что интересное, упрощенное: x=rand(1,10);y=x(magic(3)). Используя линейный линейный целочисленный индекс 3x3 для индексации вектора, вы получаете матрицу 3x3. - person Daniel; 30.03.2020
comment
@Daniel. Да, что касается формы вывода, этот пост, на который я указал в своем ответе, очень подробный - person Luis Mendo; 30.03.2020