Оси и транслирование
Функция np.sum без аргументов складывает все элементы массива. У таблицы признаков такое число бесполезно: площадь квартиры складывается с её ценой. Нужна сумма или среднее по каждому столбцу отдельно:
import numpy as np
X = np.array([[1.0, 20.0], [2.0, 35.0], [3.0, 50.0]])
print(np.sum(X)) # 111.0
print(np.sum(X, axis=0)) # [ 6. 105.]
print(X.mean(axis=0)) # [ 2. 35.]
print(X.mean(axis=1)) # [10.5 18.5 26.5]Аргумент axis
Ось (axis) — номер измерения массива. У двумерного массива ось 0 нумерует строки, ось 1 — столбцы. Аргумент axis называет ось, вдоль которой идёт подсчёт, и эта ось исчезает из результата.
X.mean(axis=0) усредняет строки и даёт по одному числу на столбец, то есть форму (2,). X.mean(axis=1) даёт по одному числу на строку, форму (3,). Метод .sum и функции np.sum, np.mean принимают axis так же. Без axis подсчёт идёт по всем элементам сразу, как в первой строке примера.
Транслирование
Средние по столбцам можно вычесть из всей таблицы одной строкой, хотя формы разные: (3, 2) и (2,). Это транслирование (broadcasting): numpy повторяет меньший массив для каждой строки большего. Умножение массива на число, как a * 1.2, — тоже транслирование: число повторяется для каждого элемента.
centered = X - X.mean(axis=0)
print(centered.shape) # (3, 2)
print(centered[:, 1]) # [-15. 0. 15.]
print(np.ones((4, 3)).shape) # (4, 3)Формы сравниваются с конца. Длины в каждой паре должны совпасть, или одна из них должна быть 1. У (3, 2) и (2,) последние длины равны, поэтому вычитание проходит. Функция np.ones создаёт массив заданной формы из единиц — так удобно проверять формы.
После вычитания средних среднее каждого столбца равно нулю. Это видно по centered[:, 1]: значения -15, 0 и 15 в сумме дают ноль. Так признаки с разными единицами приводят к общему центру.
Частая ошибка
Из каждой строки вычитают её среднее:
row_means = X.mean(axis=1)
print(X - row_means) # ✗ValueError: operands could not be broadcast together with shapes (3,2) (3,)Средних три, но numpy сравнивает последние длины: 2 и 3 не совпадают. Нужен столбец формы (3, 1): его даёт X.mean(axis=1, keepdims=True), и тогда каждое среднее вычитается из своей строки.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.