Здесь происходит несколько вещей: векторный оператор 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 очень мощное и хорошо стоит читать.
Очень подробное и хорошее объяснение. Большинство людей, проходящих курс Udacity Deep Learning, должны были наткнуться на этот ответ. – AgentX