Учебник по NumPy
Изучите NumPy с нуля: создание и индексация массивов, reshape, broadcasting, агрегация и линейная алгебра с примерами на Python.
NumPy (Numerical Python) — фундаментальная библиотека для численных вычислений в Python. Она вводит ndarray — быстрый многомерный array с фиксированным типом данных — и дополняет его сотнями математических функций, работающих сразу со всеми элементами array. На NumPy построено практически каждое научное Python-расширение (Pandas, SciPy, Matplotlib, scikit-learn).
Эта глава охватывает:
- Что такое NumPy и почему он быстрее обычных Python-списков
- Установку NumPy и стандартное соглашение об импорте
- Создание массивов с помощью
np.array,np.zeros,np.ones,np.arangeиnp.linspace - Индексацию, срезы и булеву маскировку
- Изменение формы и транспонирование
- Broadcasting — операции над массивами разных форм
- Функции агрегации (
sum,mean,std,min,max) - Поэлементные вычисления и линейную алгебру
- Вспомогательные функции (
sort,unique,where,concatenate)
Что такое NumPy?
NumPy — это библиотека Python с открытым исходным кодом, которая предоставляет:
- Мощный N-мерный array-объект (
ndarray). - Поэлементные математические функции (ufuncs), применяемые к каждому элементу array в скомпилированном коде C, а не в Python-цикле.
- Инструменты линейной алгебры, преобразования Фурье и генерации случайных чисел.
Почему NumPy быстрее Python-списков
Python-список может хранить элементы любого типа, поэтому каждый из них содержит метку типа и указатель на фактическое значение. NumPy-массивы хранят сырые числовые данные в непрерывном блоке памяти — без указателей и поиска типов. В сочетании с векторизованными C-циклами (ufuncs) операции над NumPy array из миллиона элементов выполняются в 10–100 раз быстрее, чем эквивалентный код с Python-циклом for.
Установка NumPy
NumPy входит в дистрибутив Anaconda. Для установки вручную через pip:
pip install numpyИмпорт NumPy
Общепринятое соглашение — импортировать NumPy как np:
import numpy as npВо всех примерах этой главы предполагается, что этот импорт уже выполнен.
Создание массивов
Из Python-списка
Передайте любой список (или список списков) в np.array():
[1 2 3 4 5]
int64
(5,)Двумерный array (матрица) создаётся из списка списков:
[[1 2 3]
[4 5 6]
[7 8 9]]
(3, 3)Быстрые способы создания массивов
| Функция | Что создаёт |
|---|---|
np.zeros((2, 3)) | Array из 0.0 формы (2, 3) |
np.ones(4, dtype=int) | Array из 1 формы (4,) |
np.eye(3) | Единичная матрица 3×3 |
np.arange(start, stop, step) | Как Python range(), возвращает array |
np.linspace(start, stop, n) | n равномерно распределённых значений от start до stop |
import numpy as np
print(np.zeros((2, 3)))
print(np.ones(4, dtype=int))
print(np.arange(0, 10, 2))
print(np.linspace(0, 1, 5))[[0. 0. 0.]
[0. 0. 0.]]
[1 1 1 1]
[0 2 4 6 8]
[0. 0.25 0.5 0.75 1. ]np.linspace особенно удобен, когда нужно получить точное количество точек — например, при подготовке оси X для графика. О том, как использовать его совместно с функциями построения графиков, рассказывается в главе Введение в Matplotlib.
Индексация и срезы
Индексация и срезы одномерного массива
NumPy использует тот же синтаксис [start:stop:step], что и Python-списки, а также поддерживает отрицательные индексы и шаги.
import numpy as np
a = np.array([10, 20, 30, 40, 50])
print(a[0]) # first element
print(a[-1]) # last element
print(a[1:4]) # elements at index 1, 2, 3
print(a[::2]) # every other element10
50
[20 30 40]
[10 30 50]Индексация двумерного массива
Для двумерного array используйте запись [row, col]:
import numpy as np
b = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(b[1, 2]) # row 1, col 2 → 6
print(b[0, :]) # first row → [1 2 3]
print(b[:, 1]) # second column → [2 5 8]
print(b[0:2, 1:3]) # sub-matrix6
[1 2 3]
[2 5 8]
[[2 3]
[5 6]]Булева маскировка
Передайте булев array в качестве индекса, чтобы выбрать только те элементы, для которых условие равно True:
import numpy as np
a = np.array([1, 2, 3, 4, 5])
print(a[a > 3]) # elements greater than 3
print(a[a % 2 == 0]) # even elements[4 5]
[2 4]Булевы маски — это идиоматическая замена в NumPy для фильтрующих списковых включений; на больших массивах они работают значительно быстрее.
Изменение формы и транспонирование
Изменение формы
np.reshape() (или метод .reshape()) возвращает представление данных с новой формой. Общее количество элементов должно оставаться прежним.
[[1 2 3]
[4 5 6]]Используйте -1 для размерности, которую NumPy должен определить автоматически:
import numpy as np
a = np.arange(12)
print(a.reshape(3, -1)) # 3 rows, NumPy infers 4 columns[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]Транспонирование
.T или np.transpose() меняет оси местами (строки ↔ столбцы для двумерных массивов):
[[1 3 5]
[2 4 6]]
(2, 3)Добавление и удаление элементов
Добавление элементов
np.append() возвращает новый плоский array — он не изменяет исходный на месте (в отличие от list.append).
[1 2 3 4 5 6]При многократном добавлении внутри цикла гораздо эффективнее накапливать данные в Python-список, а затем один раз преобразовать его в array с помощью np.array(), чем вызывать np.append() повторно.
Удаление элементов
np.delete(arr, indices) возвращает новый array с удалёнными элементами по указанным индексам:
[1 2 5]Конкатенация массивов
np.concatenate() объединяет два или более array вдоль существующей оси:
import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])
print(np.concatenate([a, b]))[1 2 3 4]Broadcasting
Broadcasting — это правило NumPy для применения операций между массивами разных форм без копирования данных. Классический пример — сложение скаляра с array:
import numpy as np
a = np.array([1, 2, 3])
print(a + 10) # 10 is broadcast across all elements[11 12 13]Более сложный случай: сложение одномерного array с каждой строкой двумерного:
import numpy as np
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)[[11 22 33]
[14 25 36]]NumPy сравнивает формы справа: (2, 3) + (3,) допустимо, так как хвостовые размерности совпадают; row концептуально растягивается до формы (2, 3) без какого-либо выделения памяти.
Математические операции
Поэлементная арифметика
Все стандартные операторы (+, -, *, /, **) работают поэлементно над массивами одинаковой формы. Соответствующие именованные функции (np.add, np.subtract, np.multiply, np.divide) удобны при передаче операций в качестве аргументов.
[5 7 9]
[ 4 10 18]
[1 4 9]Универсальные математические функции (ufuncs)
NumPy предоставляет векторизованные версии всех стандартных математических функций:
import numpy as np
a = np.array([0, 1, 4, 9, 16], dtype=float)
print(np.sqrt(a))
print(np.log(np.array([1, np.e, np.e**2]))) # natural log
print(np.sin(np.array([0, np.pi/2, np.pi])))[0. 1. 2. 3. 4.]
[0. 1. 2.]
[ 0.000e+00 1.000e+00 -8.742e-08]Малое значение вблизи нуля для sin(π) — нормальное округление в операциях с плавающей точкой: np.pi является приближением числа π.
Функции агрегации
Функции агрегации сводят array (или одну его ось) к единственному значению:
import numpy as np
a = np.array([1, 2, 3, 4, 5])
print(np.sum(a)) # 15
print(np.mean(a)) # 3.0
print(np.std(a)) # 1.4142135623730951
print(np.min(a)) # 1
print(np.max(a)) # 515
3.0
1.4142135623730951
1
5Для двумерных массивов передайте axis=0, чтобы агрегировать по столбцам, или axis=1 — по строкам:
import numpy as np
m = np.array([[1, 2, 3],
[4, 5, 6]])
print(np.sum(m, axis=0)) # column totals: [5 7 9]
print(np.sum(m, axis=1)) # row totals: [6 15][5 7 9]
[ 6 15]Линейная алгебра
np.dot() вычисляет скалярное произведение двух одномерных векторов или матричное произведение двух двумерных массивов. Для матричного умножения оператор @ (Python 3.5+) является современным сокращением.
import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])
print(np.dot(a, b)) # 1*3 + 2*4 = 11
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A @ B) # matrix product11
[[19 22]
[43 50]]np.linalg содержит более продвинутые операции:
| Функция | Назначение |
|---|---|
np.linalg.det(A) | Определитель |
np.linalg.inv(A) | Обратная матрица |
np.linalg.eig(A) | Собственные значения и векторы |
np.linalg.solve(A, b) | Решение линейной системы A·x = b |
Вспомогательные функции
Сортировка
import numpy as np
a = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print(np.sort(a)) # returns a sorted copy
print(np.argsort(a)) # indices that would sort the array[1 1 2 3 4 5 6 9]
[1 3 6 0 2 4 7 5]Уникальные значения
import numpy as np
a = np.array([1, 2, 2, 3, 3, 3])
print(np.unique(a))[1 2 3]Условный выбор с np.where
np.where(condition, x, y) возвращает x там, где условие равно True, и y в остальных позициях:
import numpy as np
a = np.array([1, 2, 3, 4, 5])
print(np.where(a > 2, a, 0))[0 0 3 4 5]NumPy и Matplotlib
NumPy и Matplotlib созданы для совместной работы. np.linspace генерирует значения по оси X; ufuncs NumPy вычисляют Y; Matplotlib строит результат:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 200)
plt.plot(x, np.sin(x), label='sin')
plt.plot(x, np.cos(x), label='cos')
plt.legend()
plt.title('Sine and Cosine')
plt.show()Для этого примера требуется Matplotlib (pip install matplotlib) и дисплей или бэкенд Agg для безголовых окружений. Подробное руководство приведено в главе Введение в Matplotlib.
Что изучить дальше
- Учебник по SciPy — научные вычисления более высокого уровня (интегрирование, оптимизация, обработка сигналов) на основе NumPy-массивов.
- Введение в Matplotlib — визуализация NumPy-массивов в виде линейных, точечных и гистограммных графиков.
- Построение графиков в Matplotlib — тонкая настройка макета фигуры, осей и стилей.