Необычное индексирование с булевой маскировкой | Numpy в Python - PullRequest
0 голосов
/ 15 июня 2019

Я наткнулся на этот фрагмент кода в Python Data Science Handbook, изменил его здесь для удобства чтения. Это довольно загадочно для меня, поскольку сочетает в себе причудливую индексацию с маскировкой, и я не могу понять, что происходит под ней.

import numpy as np
X = np.arange(12).reshape(3,4)
print("---X----\n",X)
row = np.array([0,1,2])
mask = np.array([1, 0, 1, 0], dtype=bool)
print("\n-----row vector after reshaping ----\n",row[:, np.newaxis])
print("\n ---mask  ----\n",mask)
print("\n ----result-----\n",X[row[:, np.newaxis], mask])

Вот вывод:

---X----
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

-----row vector after reshaping ----
 [[0]
 [1]
 [2]]

 ---mask  ----
 [ True False  True False]

 ----result-----
 [[ 0  2]
 [ 4  6]
 [ 8 10]]

Я понимаю, что иногда

X[row[:,np.newaxis],[1,2,3]]

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

Но код, который я выложил ранее, сбивает меня с толку. Из того, что я могу сделать вывод, второй аргумент (маска) эквивалентен [1,0,1,0] формы (4,), а первый аргумент будет

[[0],
[1],
[2]
]

формы (3,1). В таком случае оба эти аргумента должны быть переданы (3,4), а затем элементы будут выбраны, давая результирующую матрицу размера - (3,4). Да, я понимаю, что это противоречит цели концепции булевой маскировки, но мы не делаем что-то вроде X [mask], где мы получаем соответствующие значения, где mask - True. В нашем заявлении X[row[:, np.newaxis], mask]), Первый аргумент - это целочисленный массив, а второй - логический массив. Разве логический массив не преобразуется в целое число, чтобы играть вместе с первым аргументом, или логический массив сначала делает выбор столбцов, которые выглядят так:

[[0 2],
[4,6],
8,10]
]

и на этом мы применим первый аргумент.

1 Ответ

1 голос
/ 15 июня 2019

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

Вот соответствующий бит из документов

Как правило, если индекс включает в себя логический массив, результат будет идентично вставке obj.nonzero () в ту же позицию и использованию механизм индексации целочисленных массивов, описанный выше. х [ind_1, boolean_array, ind_2] эквивалентно x [(ind_1,) + boolean_array.nonzero () + (ind_2,)].

Теперь давайте просто применим это к вашему примеру:

mask.nonzero()
# (array([0, 2]),)

Итак,

(row[:, None],) + mask.nonzero()
# (array([[0],
#         [1],
#         [2]]), array([0, 2]))

- эффективный индекс. Это передает 3x2, и все как и ожидалось.

...