Коротко
a @ b— матричное произведение:(n, k) @ (k, m) → (n, m). Внутренние размеры должны совпадать.a * b— поэлементное умножение, это другое.- Вектор на вектор через
@— скалярное произведение (число); матрица на вектор — вектор. - Для массивов 3D и больше
@умножает матрицы пачкой по последним двум осям, а первые оси транслирует.np.dotдля них ведёт себя иначе — в новом коде используйте@. np.outer(x, y)— все попарные произведения,np.inner/np.dotдля векторов — скалярное произведение.
Синтаксис
a @ b # = np.matmul(a, b)
np.dot(x, y) # для векторов и матриц совпадает с @
np.inner(x, y) # скалярное произведение векторов
np.outer(x, y) # (n,) и (m,) → (n, m)| Формы | a @ b |
|---|---|
(n, k) @ (k, m) |
(n, m) |
(n, k) @ (k,) |
(n,) |
(k,) @ (k,) |
число |
(b, n, k) @ (k, m) |
(b, n, m) — пачка матриц |
Примеры
# цены 3 товаров в 2 магазинах и заказы: 2 покупателя × 3 товара
prices = np.array([[120, 110],
[ 80, 85],
[ 45, 40]]) # (3 товара, 2 магазина)
orders = np.array([[1, 2, 0],
[3, 0, 4]]) # (2 покупателя, 3 товара)orders @ prices # (2, 3) @ (3, 2) → (2, 2): стоимость заказа в каждом магазинеВывод
array([[280, 280],
[540, 490]])a = np.array([[1, 2], [3, 4]])
print(a * a) # поэлементно
a @ a # матричное произведениеВывод
[[ 1 4]
[ 9 16]]
array([[ 7, 10],
[15, 22]])v = np.array([1, 0, 2])
print(orders @ v) # матрица на вектор → вектор (2,)
v @ v # вектор на вектор → число (скалярное произведение)Вывод
[ 1 11] np.int64(5)
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(np.dot(x, y), np.inner(x, y)) # скалярное произведение
np.outer(x, y) # все попарные произведения (3, 3)Вывод
32 32
array([[ 4, 5, 6],
[ 8, 10, 12],
[12, 15, 18]])batch = np.ones((10, 2, 3)) # 10 матриц 2 × 3
(batch @ prices).shape # каждая умножается на pricesВывод
(10, 2, 2)
Подводные камни
Внутренние размеры не совпадают
Проверьте формы: у (2, 3) @ (2, 3) внутренние размеры 3 и 2. Скорее всего, нужна транспонированная матрица: orders @ orders.T.
orders @ orders # (2, 3) @ (2, 3): 3 ≠ 2Ошибка
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)
np.dot и @ для многомерных массивов
a = np.ones((2, 3, 4))
b = np.ones((2, 4, 5))
print((a @ b).shape) # попарно по первой оси
np.dot(a, b).shape # np.dot для 3D делает совсем другоеВывод
(2, 3, 5) (2, 3, 2, 5)
@ с числом
2 @ orders # на число умножают через *Ошибка
ValueError: matmul: Input operand 0 does not have enough dimensions (has 0, gufunc core with signature (n?,k),(k,m?)->(n?,m?) requires 1)