Массивы NumPy
Данные для машинного обучения (machine learning) — это таблицы из тысяч чисел. Список Python может их хранить, но считать по нему приходится в цикле, по одному элементу:
import numpy as np
prices = [120, 95, 300, 210]
with_tax = []
for p in prices:
with_tax.append(p * 1.2)
print(with_tax) # [144.0, 114.0, 360.0, 252.0]
a = np.array(prices)
print(a * 1.2) # [144. 114. 360. 252.]Библиотека numpy хранит числа в массиве (array) и выполняет арифметику сразу над всеми элементами. Функция np.array превращает список в массив, а выражение a * 1.2 умножает каждый элемент без цикла. Такую запись называют векторизацией (vectorization). Она короче цикла, а на тысячах строк работает в десятки раз быстрее.
Форма и тип
У массива есть атрибут shape — кортеж длин по каждому измерению. Массив a одномерный, его форма (4,).
Таблица задаётся списком строк и становится двумерным массивом. Форма (3, 2) значит три строки и два столбца. Для такого массива len(X) возвращает число строк, то есть X.shape[0].
X = np.array([[1.5, 20.0], [2.0, 35.0], [0.5, 12.0]])
print(X.shape) # (3, 2)
print(X.dtype) # float64
print(np.array([1, 2.5]).dtype) # float64
print(a / 2) # [ 60. 47.5 150. 105. ]Атрибут dtype — тип элементов (data type), один на весь массив. Дробные числа хранятся как float64. Если в списке смешаны целые и дробные числа, numpy приводит все элементы к дробному типу.
Массив из одних целых чисел получает целый тип, но деление a / 2 всё равно даёт дробные числа. Общий тип и делает арифметику быстрой: numpy не проверяет каждый элемент отдельно, как это приходится делать циклу Python.
Сумма и среднее
Функции np.sum и np.mean считают сумму и среднее элементов. У среднего есть и метод: a.mean() даёт то же число. Арифметика между массивом и числом применяется к каждому элементу, поэтому отклонения от среднего записываются одной строкой:
print(np.sum(a), np.mean(a), a.mean()) # 725 181.25 181.25
print(a - a.mean()) # [-61.25 -86.25 118.75 28.75]
print(np.array([1, 2, 3]) + np.array([10, 20, 30])) # [11 22 33]Два массива одной формы складываются поэлементно: первый элемент с первым, второй со вторым.
Частая ошибка
Арифметику применили к списку, а не к массиву:
doubled = prices * 2 # ✗
print(doubled) # [120, 95, 300, 210, 120, 95, 300, 210]Python не сообщает об ошибке. Умножение списка на целое число повторяет список, а сложение двух списков склеивает их. Умножение списка на дробное число вызывает TypeError. Превратите список в массив вызовом np.array(prices), и тогда * 2 удвоит каждое число.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.