Матрично-векторные произведения через оператор @
Содержание курса
В прошлом уроке мы разбирались с broadcasting — как NumPy согласовывает формы массивов при поэлементных операциях. Оператор @, который появляется в этом уроке, работает по совсем другой логике: он не растягивает размеры и не работает поэлементно. Он вычисляет матричное произведение, и правила совместимости у него свои.
Оператор @ и его эквивалент np.matmul
Оператор @ появился в Python 3.5 специально для матричного умножения. До него приходилось писать np.matmul(A, B) или np.dot(A, B) — @ просто делает запись короче и читаемее. Под капотом A @ B и np.matmul(A, B) — одно и то же.
Важно сразу разграничить три оператора, которые легко перепутать:
*— поэлементное умножение: каждый элемент A умножается на соответствующий элемент B, форма массивов должна быть совместима по broadcasting.np.dot— для одномерных массивов ведёт себя как скалярное произведение, для двумерных — как матричное умножение, но поведение на трёхмерных и выше отличается от@.@(np.matmul) — матричное умножение в строгом смысле: строки левого операнда умножаются на столбцы правого и суммируются.
Разница между * и @ хорошо видна на простом примере:
import numpy as np
A = np.array([[1, 2],
[3, 4]])
B = np.array([[1, 0],
[0, 1]])
print(A * B) # поэлементно: [[1, 0], [0, 4]]
print(A @ B) # матричное: [[1, 2], [3, 4]]
Для единичной матрицы B разница особенно наглядна: * обнуляет недиагональные элементы, тогда как @ возвращает саму матрицу A — ровно так, как работает умножение на единичную матрицу в линейной алгебре.
Ещё одна деталь: @ не изменяет исходные массивы — результат записывается в новый объект. A и B после операции остаются прежними.
