NumPy: массивы и вычисления в Python
Библиотека NumPy в Python с нуля: установка, создание массивов, dtype, shape и reshape, векторные операции, срезы, broadcasting и полезные функции.
Содержание · 11 разделов
- Установка NumPy
- Массив ndarray и чем он отличается от списка
- Типы данных: dtype
- Форма массива: shape и reshape
- Векторные операции
- Индексы и срезы
- Broadcasting: операции с массивами разной формы
- Полезные функции
- Частые ошибки
- ValueError: The truth value of an array … is ambiguous
- nan портит среднее
- Массив из строк вместо чисел
- Списки разной длины
- Неожиданное изменение исходных данных
- Частые вопросы
- Как сохранить массив в файл и загрузить обратно?
- Как добавить элемент к массиву?
- Как найти индексы элементов по условию?
- Как убрать экспоненциальную запись при выводе?
- Чем NumPy отличается от pandas?
- Итог
NumPy — библиотека Python для работы с числовыми массивами: она хранит данные компактно и выполняет математику сразу над всем массивом, без циклов for. На NumPy построены pandas, Matplotlib, scikit-learn и OpenCV. Короткий ответ, как начать работать с numpy в Python:
import numpy as np
a = np.array([1, 2, 3, 4])
print(a * 2) # → [2 4 6 8]
print(a.sum(), a.mean()) # → 10 2.5
Ниже — установка, создание массивов, типы данных, форма и reshape, векторные операции, срезы, broadcasting и функции, которые нужны каждый день. Примеры проверены на NumPy 2.5 и Python 3.12.
Установка NumPy
Библиотека NumPy не входит в стандартную библиотеку Python. Установите её через pip, лучше в виртуальном окружении проекта:
# Windows
py -m pip install numpy
# macOS / Linux
python3 -m pip install numpy
Проверка:
import numpy as np
print(np.__version__) # → 2.5.3 (у вас может быть другая версия)
Псевдоним np — общепринятое соглашение, его используют документация и почти все примеры. Если импорт падает с ModuleNotFoundError: No module named 'numpy', пакет установлен в другой интерпретатор — подробности в статье про ModuleNotFoundError и в руководстве по установке библиотек Python.
Массив ndarray и чем он отличается от списка
Главный объект NumPy — массив ndarray. В отличие от списка Python, все его элементы имеют один тип, а операции применяются поэлементно:
print([1, 2, 3] * 2) # → [1, 2, 3, 1, 2, 3] — список повторился
print(np.array([1, 2, 3]) * 2) # → [2 4 6] — каждый элемент умножен
Способы создать массив:
np.array([1, 2, 3]) # из списка
np.zeros(3) # → [0. 0. 0.]
np.ones((2, 3)) # матрица 2×3 из единиц
np.full(3, 7) # → [7 7 7]
np.arange(0, 10, 2) # → [0 2 4 6 8] — как range()
np.linspace(0, 1, 5) # → [0. 0.25 0.5 0.75 1. ] — 5 точек от 0 до 1 включительно
np.eye(2) # единичная матрица 2×2
Обратите внимание: zeros и ones по умолчанию создают дробные числа (float64), поэтому в выводе стоят точки. Размер многомерного массива передаётся кортежем: np.ones((2, 3)), а не np.ones(2, 3).
Основные атрибуты массива:
m = np.array([[1, 2, 3], [4, 5, 6]])
print(m.shape) # → (2, 3) — 2 строки, 3 столбца
print(m.ndim) # → 2 — число измерений
print(m.size) # → 6 — всего элементов
print(m.dtype) # → int64 — тип элементов
Типы данных: dtype
NumPy определяет тип по содержимому, а задать его можно параметром dtype:
print(np.array([1, 2, 3]).dtype) # → int64
print(np.array([1.5, 2, 3]).dtype) # → float64 — одно дробное число делает дробным весь массив
print(np.array([1, 2, 3], dtype=np.float32)) # → [1. 2. 3.]
print(np.array([True, False]).dtype) # → bool
Преобразовать готовый массив — метод astype(). Он создаёт новый массив; дробная часть при переводе в целые отбрасывается, а не округляется:
print(np.array([1.7, 2.2]).astype(int)) # → [1 2]
Основные типы:
| dtype | Что хранит |
|---|---|
int64, int32 | целые числа со знаком |
uint8 | целые от 0 до 255 (пиксели) |
float64, float32 | дробные числа |
bool | True / False |
<U… (например <U2) | строки Unicode фиксированной длины |
object | произвольные объекты Python |
Важно: у типов фиксированного размера есть переполнение.
np.array([200], dtype=np.uint8) + 100даёт[44], а не 300 — значение «перешло через ноль» без ошибки.
Форма массива: shape и reshape
Метод reshape() меняет форму без изменения данных. Произведение новых размеров должно совпадать с числом элементов, а -1 означает «вычисли сам»:
r = np.arange(12)
print(r.reshape(3, 4))
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(r.reshape(2, -1).shape) # → (2, 6)
print(r.reshape(3, 4).T.shape) # → (4, 3) — транспонирование
print(r.reshape(3, 4).ravel()) # → [ 0 1 2 3 4 5 6 7 8 9 10 11] — снова одномерный
Если размеры не подходят, будет ошибка:
r.reshape(5, 3)
# ValueError: cannot reshape array of size 12 into shape (5,3)
Векторные операции
Арифметика между массивами одинаковой формы выполняется поэлементно. Это и есть векторизация: цикл работает внутри NumPy на C, а не в интерпретаторе Python, поэтому на больших массивах это заметно быстрее ручного for.
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
print(a + b) # → [11 22 33]
print(a * b) # → [10 40 90]
print(b / a) # → [10. 10. 10.] — деление всегда даёт float
print(a ** 2) # → [1 4 9]
print(np.sqrt(a)) # → [1. 1.41421356 1.73205081]
print(a > 1) # → [False True True]
print(a @ b) # → 140 — скалярное произведение
Оператор @ (или np.dot) выполняет матричное умножение, а * — поэлементное. Для матриц 2×2 разница видна сразу:
print(np.array([[1, 2], [3, 4]]) @ np.array([[5, 6], [7, 8]]))
# [[19 22]
# [43 50]]
Индексы и срезы
Одномерный массив режется так же, как список:
a = np.arange(10)
print(a[2:5], a[-1], a[::2]) # → [2 3 4] 9 [0 2 4 6 8]
print(a[::-1]) # → [9 8 7 6 5 4 3 2 1 0]
В многомерном массиве индексы по осям перечисляются через запятую: m[строка, столбец].
m = np.arange(1, 13).reshape(3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
print(m[0, 1]) # → 2
print(m[1]) # → [5 6 7 8] — вторая строка
print(m[:, 0]) # → [1 5 9] — первый столбец
print(m[:2, 1:3]) # подматрица: строки 0–1, столбцы 1–2
# [[2 3]
# [6 7]]
Булева маска отбирает элементы по условию, а список индексов — элементы на нужных позициях:
print(m[m > 6]) # → [ 7 8 9 10 11 12]
print(a[[0, 3, 5]]) # → [0 3 5]
Маской удобно заменять значения, а np.where() выбирает между двумя вариантами:
t = np.array([-2, 5, -1, 8])
print(np.where(t > 0, t, 0)) # → [0 5 0 8] — новый массив
t[t < 0] = 0 # изменение на месте
print(t) # → [0 5 0 8]
Важно: обычный срез — это представление (view), а не копия. Изменение среза меняет исходный массив. Нужна независимая копия — вызовите
.copy().
a = np.arange(10)
s = a[2:5]
s[0] = 100
print(a) # → [ 0 1 100 3 4 5 6 7 8 9]
Broadcasting: операции с массивами разной формы
Broadcasting («растягивание») позволяет выполнять операции над массивами разной формы. NumPy сравнивает размеры с конца: оси совместимы, если они равны или одна из них равна 1. Число «растягивается» на весь массив, строка — на каждую строку, столбец — на каждый столбец:
m = np.array([[1, 2, 3], [4, 5, 6]]) # форма (2, 3)
print(m + 10)
# [[11 12 13]
# [14 15 16]]
print(m + np.array([10, 20, 30])) # форма (3,) — прибавляется к каждой строке
# [[11 22 33]
# [14 25 36]]
print(m + np.array([[100], [200]])) # форма (2, 1) — к каждому столбцу
# [[101 102 103]
# [204 205 206]]
Если размеры несовместимы, NumPy сообщит об этом:
m + np.array([1, 2])
# ValueError: operands could not be broadcast together with shapes (2,3) (2,)
Чтобы прибавить вектор длины 2 к строкам, превратите его в столбец: np.array([1, 2]).reshape(2, 1).
Полезные функции
Агрегирующие функции принимают параметр axis: axis=0 — по столбцам (сверху вниз), axis=1 — по строкам:
d = np.array([[1, 2, 3], [4, 5, 6]])
print(d.sum()) # → 21
print(d.sum(axis=0)) # → [5 7 9]
print(d.sum(axis=1)) # → [ 6 15]
print(d.max(), d.argmax()) # → 6 5 — максимум и его индекс в «развёрнутом» массиве
print(d.mean(axis=0)) # → [2.5 3.5 4.5]
print(d.std().round(3)) # → 1.708
| Функция | Что делает |
|---|---|
sum, mean, min, max, std | сумма, среднее, минимум, максимум, СКО |
argmin, argmax | индекс минимума / максимума |
np.cumsum | накопленная сумма |
np.sort, np.unique | сортировка, уникальные значения |
np.round | округление до заданного числа знаков |
np.concatenate, np.vstack | склеить массивы подряд / друг под другом |
np.where | выбор по условию |
np.isnan, np.nanmean, np.nansum | работа с пропусками nan |
.tolist() | вернуть обычный список Python |
Случайные числа в современном NumPy получают через генератор default_rng. С фиксированным seed результат воспроизводится:
rng = np.random.default_rng(42)
print(rng.integers(1, 7, size=5)) # → [1 5 4 3 3] — пять бросков кубика
print(rng.random(3).round(3)) # → [0.697 0.094 0.976]
Частые ошибки
ValueError: The truth value of an array … is ambiguous
Сравнение массивов возвращает массив, а не одно значение, поэтому его нельзя ставить в if:
a = np.array([1, 2])
if a == np.array([1, 2]):
...
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Используйте (a == b).all(), (a == b).any() или np.array_equal(a, b).
nan портит среднее
Одно значение np.nan превращает результат mean() и sum() в nan, а np.nan == np.nan даёт False. Проверяйте пропуски через np.isnan() и считайте np.nanmean():
x = np.array([1, np.nan, 3])
print(np.mean(x), np.nanmean(x)) # → nan 2.0
Массив из строк вместо чисел
Если в списке смешаны числа и строки, NumPy приведёт всё к строкам: np.array([1, "a"]) даст ['1' 'a'] с dtype <U21. Арифметика с таким массивом не работает — очистите данные до создания массива.
Списки разной длины
np.array([[1, 2], [3]])
# ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape ...
Массив NumPy всегда «прямоугольный». Выровняйте длины вложенных списков или храните такие данные в обычных списках.
Неожиданное изменение исходных данных
Срез — это view, поэтому функция, которая меняет переданный срез, меняет и исходный массив. Если данные нужно сохранить, работайте с .copy().
Частые вопросы
Как сохранить массив в файл и загрузить обратно?
Формат .npy сохраняет массив вместе с формой и dtype, текстовый CSV удобен для обмена с другими программами:
m = np.arange(6).reshape(2, 3)
np.save("data.npy", m)
m2 = np.load("data.npy") # тот же массив, та же форма
np.savetxt("data.csv", m, delimiter=",", fmt="%d")
m3 = np.loadtxt("data.csv", delimiter=",", dtype=int)
Несколько массивов в одном файле сохраняет np.savez("arrays.npz", x=x, y=y).
Как добавить элемент к массиву?
np.append() не меняет исходный массив, а создаёт новый с копией всех данных:
a = np.array([1, 2, 3])
b = np.append(a, 4)
print(a, b) # → [1 2 3] [1 2 3 4]
В цикле это медленно — каждая итерация копирует весь массив. Собирайте значения в обычный список, а массив создавайте один раз в конце: np.array(rows).
Как найти индексы элементов по условию?
np.flatnonzero() возвращает позиции элементов одномерного массива, для которых условие истинно; np.argwhere() — пары индексов в многомерном:
t = np.array([3, 8, 1, 9, 4])
print(np.flatnonzero(t > 3)) # → [1 3 4]
m = np.array([[1, 7], [8, 2]])
print(np.argwhere(m > 5))
# [[0 1]
# [1 0]]
np.where(t > 3) с одним аргументом даёт те же индексы, но в виде кортежа массивов — по одному на каждую ось.
Как убрать экспоненциальную запись при выводе?
Если в массиве есть очень маленькие и большие числа, NumPy печатает их в виде 1.2345678e+04. Формат вывода меняет np.set_printoptions():
x = np.array([0.000123, 12345.678, 1.5])
np.set_printoptions(suppress=True, precision=3)
print(x) # → [ 0. 12345.678 1.5 ]
Настройка влияет только на печать — сами значения в массиве не округляются.
Чем NumPy отличается от pandas?
NumPy работает с однородными числовыми массивами по позициям: быстрая математика, матрицы, изображения. pandas построен поверх NumPy и добавляет подписи строк и столбцов, разные типы в разных столбцах, пропуски, группировку и чтение CSV или Excel. Для таблиц с данными удобнее pandas, для вычислений над числами — NumPy; DataFrame превращается в массив методом df.to_numpy().
Итог
NumPy заменяет циклы над числами операциями над целыми массивами: создайте ndarray, следите за dtype и shape, выбирайте данные срезами и масками, а broadcasting возьмёт на себя операции с массивами разной формы. Табличные данные с подписями столбцов удобнее обрабатывать в pandas, а результаты вычислений — показать на графике с помощью Matplotlib. Другие популярные пакеты собраны в обзоре библиотек Python, полный справочник — в документации NumPy.
- #Python
- #NumPy
- #Массивы
- #Анализ данных