Скидка на товар или на магазин: проверяем ось broadcasting
Матрица цен имеет три магазина и три товара. Вектор скидок тоже длины три. Умножение проходит без ошибки, но скидки магазинов применяются к товарам. Равные размеры скрыли неправильный смысл оси.
Подписать измерения до вычисления
Пусть строки — магазины, столбцы — товары. Вектор формы (3,) сопоставляется с последней осью, поэтому три коэффициента относятся к товарам. Если скидка задаётся магазину, нужна форма (3, 1): отдельное значение строки распространяется по всем её столбцам.
Broadcasting проверяет совместимость размеров справа налево. Он не знает названий измерений. Когда число магазинов равно числу товаров, оба выражения допустимы, и проверка одной shape не найдёт ошибку. В контрольном входе полезно также использовать прямоугольную матрицу.
Проверить конкретный элемент
Ниже скидки магазинов равны 10%, 20% и 30%. Новая ось в discounts[:, None] делает намерение явным. Проверяем целую строку и один товар другого магазина. Сверка только общей суммы слабее: разные ошибки распределения способны частично компенсироваться.
Идентификаторы магазинов и товаров должны храниться рядом с матрицей. Если векторы построены из разных сортировок таблиц, правильная форма всё равно не гарантирует правильного соответствия.
import numpy as np
prices = np.array([[100., 200., 300.], [100., 200., 300.], [100., 200., 300.]])
discounts = np.array([0.1, 0.2, 0.3])
assert prices.shape[0] == discounts.size
result = prices * (1 - discounts[:, None])
wrong_axis = prices * (1 - discounts)
print(result)
assert np.allclose(result[0], [90, 180, 270])
assert result[1, 0] == 80
assert not np.allclose(result, wrong_axis)Первая строка уменьшилась на 10% целиком. В неправильном варианте первый товар уменьшается на 10% во всех магазинах. Оба результата имеют одинаковую форму, но отвечают на разные вопросы.
Сохранить смысл при смене формы
Зафиксируйте в функции ожидаемое число измерений и длину вектора соответствующей оси. Если добавится измерение даты, прежнее выражение может снова оказаться допустимым и неверным. Подписывайте порядок осей в интерфейсе расчёта и проверяйте его при преобразовании из DataFrame.
Не используйте reshape только для устранения ValueError. Выбор формы должен следовать из вопроса: коэффициент относится к товару, магазину или отдельной паре? Для пар нужна полноценная матрица коэффициентов, для магазина — столбец, для товара — строковый вектор.
Для больших массивов оцените форму результата до операции. Broadcasting не обязан копировать маленький вектор, но вычисление всё равно создаёт итоговый массив. Случайное добавление двух новых осей может породить огромный трёхмерный результат вместо таблицы.
Оставьте адресные проверки с разными ценами и коэффициентами. Одинаковые значения всех скидок не обнаружат перепутанную ось. Проверяемый пример должен различать допустимые по форме, но разные по смыслу вычисления.
Закрепить на практике
В бесплатном уроке broadcasting вы разберёте совместимость форм и исправление несовместимости. После задач используйте пример статьи: объясните, какому объекту принадлежит коэффициент, прежде чем добавлять ось. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.
Продолжить на практике
- NumPy и pandas: практический тренажёр ↗
Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.
