Как работает «Необычное индексирование с широковещательной передачей и логическим маскированием»? - PullRequest
0 голосов
/ 27 января 2020

Я наткнулся на этот фрагмент кода в Руководстве по науке о данных Джейка Вандерпласа. Концепция использования вещания вместе с необычным индексированием не была мне понятна. Пожалуйста, объясните.

In[5]: X = np.arange(12).reshape((3, 4))
 X
Out[5]: array([[ 0, 1, 2, 3],
 [ 4, 5, 6, 7],
 [ 8, 9, 10, 11]])

In[6]: row = np.array([0, 1, 2])
 col = np.array([2, 1, 3])

In[7]: X[row[:, np.newaxis], col]
Out[7]: array([[ 2, 1, 3],
               [ 6, 5, 7],
              [10, 9, 11]])

В нем говорится: «Здесь каждое значение строки сопоставляется с каждым вектором столбца, точно так, как мы видели при трансляции арифметических операций c. Например:«

In[8]: row[:, np.newaxis] * col
Out[8]: array([[0, 0, 0],
               [2, 1, 3],
               [4, 2, 6]])

1 Ответ

0 голосов
/ 27 января 2020

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

arr55 = np.arange(25).reshape((5, 5))
# array([[ 0,  1,  2,  3,  4],
#        [ 5,  6,  7,  8,  9],
#        [10, 11, 12, 13, 14],
#        [15, 16, 17, 18, 19],
#        [20, 21, 22, 23, 24]])

arr53 = arr55[:, [3, 3, 4]]  
# pick the elements at (arr[:, 3], arr[:, 3], arr[:, 4])
# array([[ 3,  3,  4],
#        [ 8,  8,  9],
#        [13, 13, 14],
#        [18, 18, 19],
#        [23, 23, 24]])

Таким образом, если вы индексируете массив (m, n) с индексом строки (или столбца) длины k (или длины l), результирующая фигура будет иметь вид:

A_nm[row, :] -> A_km
A_nm[:, col] -> A_nl

Если, однако, Вы используете два массива row и col для индексации массива, который вы l oop, по обоим индексам одновременно и складываете элементы (все еще могут быть массивами) в соответствующей позиции вместе. Здесь row и col должны иметь одинаковую длину.

A_nm[row, col] -> A_k
array([ 3, 13, 24])

arr3 = arr55[[0, 2, 4], [3, 3, 4]]  
# pick the element at (arr[0, 3], arr[2, 3], arr[4, 4])

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

(arr[0, 3], arr[2, 3], arr[4, 4])

, а скорее расширенная версия:

(arr[0, [3, 3, 4]], arr[2, [3, 3, 4]], arr[4, [3, 3, 4]])
# each row value is matched with each column vector

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

row * col  
# performs a element wise multiplication resulting in 3 
numbers
row[:, np.newaxis] * col 
# performs a multiplication where each row value is *matched* with each column vector

В примере требуется подчеркнуть это соответствие row и col.

Мы можем посмотреть и поиграть вокруг с различными возможностями:

n = 3
m = 4
X = np.arange(n*m).reshape((n, m))
row = np.array([0, 1, 2])  # k = 3
col = np.array([2, 1, 3])  # l = 3

X[row, :]  # A_nm[row, :] -> A_km
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]])

X[:, col]  # A_nm[:, col] -> A_nl
# array([[ 2,  1,  3],
#        [ 6,  5,  7],
#        [10,  9, 11]])

X[row, col]  # A_nm[row, col] -> A_l == A_k
# array([ 2,  5, 11]

X[row, :][:, col]  # A_nm[row, :][:, col] -> A_km[:, col] -> A_kl 
# == X[:, col][row, :]
# == X[row[:, np.newaxis], col]  # A_nm[row[:, np.newaxis], col] -> A_kl 
# array([[ 2,  1,  3],
#        [ 6,  5,  7],
#        [10,  9, 11]])

X[row, col[:, np.newaxis]]
# == X[row[:, np.newaxis], col].T
# array([[ 2,  6, 10],
#        [ 1,  5,  9],
#        [ 3,  7, 11]])

...