Покупатель взял 2 пачки кофе по 150 ₽, 1 кружку за 220 ₽ и 3 печенья по 90 ₽. Сколько он заплатил? Нужно
перемножить количества на цены попарно и сложить: 2·150 + 1·220 + 3·90 = 790. Эта операция — «умножить
попарно и сложить» — встречается в анализе данных постоянно, и у неё есть своё имя.
Скалярное произведение
Сумму попарных произведений двух массивов одинаковой длины называют скалярным произведением (dot product).
Его можно собрать из знакомых частей — (q * p).sum() — или получить сразу: функцией np.dot(q, p) или
оператором @:
import numpy as np
q = np.array([2, 1, 3]) # сколько штук
p = np.array([150, 220, 90]) # цена штуки
print(q * p)
print((q * p).sum())
print(np.dot(q, p))
print(q @ p)[300 220 270] 790 790 790
Итоговая оценка за курс складывается так: экзамен — 50 %, проект — 30 %, домашние задания — 20 %. В marks —
оценки одного студента в этом порядке, в weights — веса. Сохраните в final итоговую оценку.
marks @ weights.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
marks = np.array([78, 92, 85])
weights = np.array([0.5, 0.3, 0.2])
final = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
marks = np.array([78, 92, 85])
weights = np.array([0.5, 0.3, 0.2])
final = marks @ weightsТаблица на вектор
Настоящая сила @ — в таблицах. Пусть в orders пять заказов (строки) и четыре товара (столбцы): число — сколько
штук товара в заказе. Цены — массив из четырёх чисел. orders @ prices считает скалярное произведение каждой
строки на цены — сумму каждого заказа — за одну операцию:
orders = np.array([
[2, 1, 0, 3],
[0, 2, 1, 1],
[1, 0, 4, 0],
[3, 3, 0, 2],
[0, 1, 2, 5],
])
prices = np.array([180, 250, 90, 60])
print(orders.shape, prices.shape)
print(orders @ prices)(5, 4) (4,) [ 790 650 540 1410 730]
Формы: таблица (5, 4) @ вектор (4,) → (5,). Число столбцов таблицы должно совпасть с длиной вектора —
каждому товару своя цена. Если они не совпадают, NumPy сообщает об ошибке:
orders @ np.array([180, 250, 90])ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 3 is different from 4)
В scores — оценки четырёх студентов (строки) за экзамен, проект и домашние задания (столбцы). Сохраните в
finals итоговые оценки всех студентов с весами weights из прошлого упражнения, а в best — номер строки
студента с лучшим итогом.
scores @ weights.argmax.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
scores = np.array([
[78, 85, 90],
[62, 70, 58],
[91, 88, 95],
[55, 80, 72],
])
finals = ...
best = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
scores = np.array([
[78, 85, 90],
[62, 70, 58],
[91, 88, 95],
[55, 80, 72],
])
finals = scores @ weights
best = finals.argmax()Таблица на таблицу
Если справа не вектор, а таблица, @ считает скалярное произведение каждой строки левой таблицы на каждый
столбец правой. Добавим к ценам второй столбец — вес товара в граммах. Тогда orders @ price_weight даст
сразу два итога по каждому заказу — сумму и вес посылки:
price_weight = np.array([
[180, 250], # цена, ₽; вес, г
[250, 300],
[90, 100],
[60, 50],
])
print(orders.shape, price_weight.shape)
print(orders @ price_weight)(5, 4) (4, 2) [[ 790 950] [ 650 750] [ 540 650] [1410 1750] [ 730 750]]
Например, число в строке 0, столбце 1 — вес первого заказа: строка 0 orders (2, 1, 0, 3) на столбец 1
price_weight (250, 300, 100, 50): 2·250 + 1·300 + 0·100 + 3·50 = 950.
Правило форм: (m, n) @ (n, k) → (m, k). Внутренние размеры (n) должны совпасть — их «съедает» сумма,
внешние (m и k) остаются.
a формы (5, 3), b формы (3, 2). Какая форма у a @ b?
(5, 3) @ (3, 2) → (5, 2). Совпадать должны именно внутренние, а не формы целиком.В price_cost — цена и себестоимость каждого из четырёх товаров (строка — товар). Посчитайте для заказов
orders таблицу rc — выручку и затраты каждого заказа, затем
сохраните в profit прибыль каждого заказа (выручка минус затраты), а в total_profit — общую прибыль.
@ таблица товаров даёт таблицу (5, 2) — столбец 0 — выручка, 1 — затраты.profit = rc[:, 0] - rc[:, 1].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
price_cost = np.array([
[180, 70], # цена, себестоимость
[250, 110],
[90, 30],
[60, 15],
])
rc = ...
profit = ...
total_profit = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
price_cost = np.array([
[180, 70], # цена, себестоимость
[250, 110],
[90, 30],
[60, 15],
])
rc = orders @ price_cost
profit = rc[:, 0] - rc[:, 1]
total_profit = profit.sum()Итоги
- Скалярное произведение — сумма попарных произведений:
np.dot(a, b),a @ bили(a * b).sum(). *— поэлементно,@— «умножить попарно и сложить».- Таблица
(m, n)@ вектор(n,)→(m,): итог по каждой строке. - Таблица
(m, n)@ таблица(n, k)→(m, k): внутренние размеры совпадают и исчезают.