Что такое NumPy?
NumPy — это фундаментальный пакет для научных вычислений в Python. Это библиотека Python, предоставляющая многомерный массив объектов, различные производные объекты (такие как маскированные массивы и матрицы), а также набор функций для быстрых операций над массивами, включая математические, логические, манипуляции с формой, сортировку, выбор, ввод/вывод, дискретные преобразования Фурье, базовые линейную алгебру, базовые статистические операции, генерацию случайных чисел и многое другое.
В основе пакета NumPy лежит объект ndarray. Он обобщает n-мерные массивы однородных типов данных, причём многие операции выполняются на предварительно скомпилированном коде для повышения производительности. Существуют некоторые важные различия между массивами NumPy и стандартными Python последовательностями:
- Массивы NumPy имеют фиксированный размер при создании, в отличие от списков Python (которые могут динамически расширяться). Изменение размера
ndarrayсоздаст новый массив и удалит исходный. - Элементы в массиве NumPy должны иметь один и тот же тип данных и, следовательно, будут иметь одинаковый размер в памяти. Исключение: можно иметь массивы (Python, включая NumPy) объектов, что позволяет создавать массивы с элементами разного размера.
- Массивы NumPy облегчают продвинутые математические и другие типы операций над большими объемами данных. Обычно такие операции выполняются более эффективно и с меньшим объемом кода, чем при использовании встроенных последовательностей Python.
- Растущее количество научных и математических пакетов на базе Python используют массивы NumPy; хотя они обычно поддерживают ввод данных в виде Python-последовательностей, они преобразуют такой ввод в массивы NumPy перед обработкой, и они часто выдают массивы NumPy. Другими словами, для эффективного использования большинства современных научных/математических программ на Python недостаточно знать, как использовать встроенные типы последовательностей Python – необходимо также уметь использовать массивы NumPy.
Аспекты размера и скорости последовательностей особенно важны в научных вычислениях. В качестве простого примера рассмотрим случай умножения каждого элемента 1-мерной последовательности на соответствующий элемент в другой последовательности той же длины. Если данные хранятся в двух списках Python, a и b, мы могли бы перебирать каждый элемент:
c = []
for i in range(len(a)):
c.append(a[i]*b[i])
Это дает правильный ответ, но если a и b содержат миллионы чисел, мы будем платить за неэффективность циклов в Python. Мы могли бы выполнить ту же задачу намного быстрее на C, написав (для ясности мы пренебрегаем объявлениями переменных и инициализацией, выделением памяти и т. д.):
for (i = 0; i < rows; i++) {
c[i] = a[i]*b[i];
}
Это экономит все накладные расходы, связанные с интерпретацией кода Python и манипулированием объектами Python, но за счёт этого теряются преимущества программирования на Python. Кроме того, объём кода увеличивается с размерностью наших данных. Например, в случае 2-мерного массива код на C (сокращённый, как и раньше) расширяется до
for (i = 0; i < rows; i++) {
for (j = 0; j < columns; j++) {
c[i][j] = a[i][j]*b[i][j];
}
}
NumPy даёт нам лучшее из обоих миров: элементные операции являются «режим по умолчанию», когда участвует ndarray, но элементная операция быстро выполняется предварительно скомпилированным кодом C. В NumPy
c = a * b
выполняет те же действия, что и предыдущие примеры, с почти скоростью C, но с простотой кода, ожидаемой от чего-то, основанного на Python. Действительно, обозначение NumPy ещё проще! Этот последний пример иллюстрирует два свойства NumPy, которые являются основой большей части его возможностей: векторизация и широковещательные передачи.
Почему NumPy быстрый?
Векторизация описывает отсутствие явных циклов, индексирования и т. д. в коде — эти вещи, конечно, происходят «за кулисами» в оптимизированном, предварительно скомпилированном коде C. Векторизированный код имеет много преимуществ, среди которых:
- векторизированный код более лаконичный и легче читается
- меньше строк кода, как правило, означает меньше ошибок
- код более точно соответствует стандартным математическим обозначениям (что облегчает, как правило, правильное кодирование математических конструкций)
- векторизация приводит к более «питоничному» коду. Без векторизации наш код был бы завален неэффективными и трудночитаемыми
forциклами.
Широковещательная передача — это термин, используемый для описания неявного элементного поведения операций; в общем случае, в NumPy все операции, не только арифметические, но и логические, побитовые, функциональные и т. д., ведут себя в этой неявной элементной манере, т. е. они широковещательны. Кроме того, в примере выше, a и b могут быть многомерными массивами одной и той же формы, или скаляр и массив, или даже два массива с разными формами, при условии, что меньший массив может быть «расширен» до формы большего таким образом, что полученное широковещательное распространение будет однозначным. Подробные «правила» широковещательной передачи см. в Широковещательные передачи.
Кто ещё использует NumPy?
NumPy полностью поддерживает объектно-ориентированный подход, начиная, еще раз, с ndarray. Например, ndarray — это класс, имеющий множество методов и атрибутов. Многие из его методов дублируются функциями в самом верхнем пространстве имен NumPy, что позволяет программисту кодировать в любом предпочтительном им парадигме. Эта гибкость позволила диалекту массивов NumPy и классу NumPy ndarray стать de-facto языком обмена многомерными данными, используемым в Python.
© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/user/whatisnumpy.html