2016-04-10 2 views
14

Я новичок в Python, и я изучаю TensorFlow. В учебном пособии с использованием набора данных noMNIST они приводят примерный код, чтобы преобразовать матрицу меток в один-на-n закодированный массив.Понимание == применяется к массиву NumPy

Цель состоит в том, чтобы принять массив, состоящий из целых чисел метки 0 ... 9, и возвращают матрицу, где каждое целое была трансформирована в кодированном массиве один из п-так:

0 -> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
1 -> [0, 1, 0, 0, 0, 0, 0, 0, 0, 0] 
2 -> [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] 
... 

Код, который они дают для этого:

# Map 0 to [1.0, 0.0, 0.0 ...], 1 to [0.0, 1.0, 0.0 ...] 
labels = (np.arange(num_labels) == labels[:,None]).astype(np.float32) 

Однако я не понимаю, как этот код делает это вообще. Похоже, он просто генерирует массив целых чисел в диапазоне от 0 до 9, а затем сравнивает это с матрицей меток и преобразует результат в float. Как оператор == приводит к закодированной в одном виде матрице?

ответ

22

Здесь происходит несколько вещей: векторный оператор numpy, добавление оси одиночной оси и трансляция.

Во-первых, вы должны уметь видеть, как делает == волшебство.

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

>>> labels = np.array([1,2,0,0,2]) 
>>> labels == 0 
array([False, False, True, True, False], dtype=bool) 
>>> (labels == 0).astype(np.float32) 
array([ 0., 0., 1., 1., 0.], dtype=float32) 

Сначала мы получим булев массив, а затем мы принуждать к поплавкам: Ложные == 0 в Python, и правда == 1. Таким образом, мы завершаем массив, который равен 0, где labels не равен 0 и 1, где он.

Но нет ничего особенного по сравнению с 0, мы могли бы сравнить с 1 или 2 или 3 вместо для аналогичных результатов:

>>> (labels == 2).astype(np.float32) 
array([ 0., 1., 0., 0., 1.], dtype=float32) 

В самом деле, мы могли бы перебираем все возможные этикетки и генерировать этот массив. Мы могли бы использовать listcomp:

>>> np.array([(labels == i).astype(np.float32) for i in np.arange(3)]) 
array([[ 0., 0., 1., 1., 0.], 
     [ 1., 0., 0., 0., 0.], 
     [ 0., 1., 0., 0., 1.]], dtype=float32) 

но это действительно не использует преимущества numpy. То, что мы хотим сделать, это каждый возможный ярлык по сравнению с каждым элементом, IOW сравнить

>>> np.arange(3) 
array([0, 1, 2]) 

с

>>> labels 
array([1, 2, 0, 0, 2]) 

А вот где магия Numpy вещания приходит. Прямо сейчас, labels является 1-мерный объект формы (5,). Если мы сделаем его двумерным объектом формы (5,1), то операция будет «транслироваться» по последней оси, и мы получим результат формы (5,3) с результатами сравнения каждой записи в диапазон с каждым элементом меток.

Во-первых, мы можем добавить «лишние» ось labels с помощью None (или np.newaxis), меняя свою форму:

>>> labels[:,None] 
array([[1], 
     [2], 
     [0], 
     [0], 
     [2]]) 
>>> labels[:,None].shape 
(5, 1) 

И тогда мы можем сделать сравнение (это транспонированная договоренности мы были смотря на ранее, но это не имеет большого значения).

>>> np.arange(3) == labels[:,None] 
array([[False, True, False], 
     [False, False, True], 
     [ True, False, False], 
     [ True, False, False], 
     [False, False, True]], dtype=bool) 
>>> (np.arange(3) == labels[:,None]).astype(np.float32) 
array([[ 0., 1., 0.], 
     [ 0., 0., 1.], 
     [ 1., 0., 0.], 
     [ 1., 0., 0.], 
     [ 0., 0., 1.]], dtype=float32) 

Вещание в numpy очень мощное и хорошо стоит читать.

+0

Очень подробное и хорошее объяснение. Большинство людей, проходящих курс Udacity Deep Learning, должны были наткнуться на этот ответ. – AgentX

0

Вкратце, == применяется к массиву numpy, что означает применение элемента-мута == к массиву. Результатом является массив булевых. Вот пример:

>>> b = np.array([1,0,0,1,1,0]) 
>>> b == 1 
array([ True, False, False, True, True, False], dtype=bool) 

Рассчитывать сказать, сколько 1s есть в b, вам не нужно, чтобы бросить массив плавать, т.е. .astype(np.float32) может быть сохранен, так как в питоне булев является подклассом int и в Python 3 у вас есть True == 1 False == 0. Так вот, как вы считаете, сколько из них находится в b:

>>> np.sum((b == 1)) 
3 

Или:

>>> np.count_nonzero(b == 1) 
3