W3docs

Учебник по 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 с открытым исходным кодом, которая предоставляет:

  1. Мощный N-мерный array-объект (ndarray).
  2. Поэлементные математические функции (ufuncs), применяемые к каждому элементу array в скомпилированном коде C, а не в Python-цикле.
  3. Инструменты линейной алгебры, преобразования Фурье и генерации случайных чисел.

Почему 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():

python— editable, runs on the server
[1 2 3 4 5]
int64
(5,)

Двумерный array (матрица) создаётся из списка списков:

python— editable, runs on the server
[[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 element
10
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-matrix
6
[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()) возвращает представление данных с новой формой. Общее количество элементов должно оставаться прежним.

python— editable, runs on the server
[[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() меняет оси местами (строки ↔ столбцы для двумерных массивов):

python— editable, runs on the server
[[1 3 5]
 [2 4 6]]
(2, 3)

Добавление и удаление элементов

Добавление элементов

np.append() возвращает новый плоский array — он не изменяет исходный на месте (в отличие от list.append).

python— editable, runs on the server
[1 2 3 4 5 6]

При многократном добавлении внутри цикла гораздо эффективнее накапливать данные в Python-список, а затем один раз преобразовать его в array с помощью np.array(), чем вызывать np.append() повторно.

Удаление элементов

np.delete(arr, indices) возвращает новый array с удалёнными элементами по указанным индексам:

python— editable, runs on the server
[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) удобны при передаче операций в качестве аргументов.

python— editable, runs on the server
[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))    # 5
15
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 product
11
[[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 — тонкая настройка макета фигуры, осей и стилей.
Was this page helpful?