NumPy (произносится как / ˈnʌmp aɪ / NUM - py ) — это библиотека для языка программирования Python , добавляющая поддержку больших многомерных массивов и матриц , а также большой набор высокоуровневых математических функций для работы с этими массивами. [ 3 ] Предшественник NumPy, Numeric, был изначально создан Джимом Хьюганином при участии нескольких других разработчиков. В 2005 году Трэвис Олифант создал NumPy, включив функции конкурирующего Numarray в Numeric с обширными модификациями. NumPy — это программное обеспечение с открытым исходным кодом , в которое вносят свой вклад многие участники. NumPy — это проект, спонсируемый NumFOCUS из финансовых средств. [4]
Язык программирования Python изначально не был разработан для численных вычислений, но привлек внимание научного и инженерного сообщества на раннем этапе. В 1995 году была основана специальная группа интересов (SIG) matrix-sig с целью определения пакета для вычисления массивов ; среди ее членов был разработчик и сопровождающий Python Гвидо ван Россум , который расширил синтаксис Python (в частности, синтаксис индексации [5] ), чтобы упростить вычисления массивов . [6]
Реализация матричного пакета была завершена Джимом Фултоном, затем обобщена [ необходимо дополнительное объяснение ] Джимом Хагунином и названа Numeric [6] (также известна как «Числовые расширения Python» или «NumPy»), с влиянием языков семейства APL , Basis, MATLAB , FORTRAN , S и S+ и других. [7] [8] Хагунин, аспирант Массачусетского технологического института (MIT), [8] : 10 присоединился к Корпорации национальных исследовательских инициатив (CNRI) в 1997 году для работы над JPython , [6] оставив Пола Дюбуа из Ливерморской национальной лаборатории имени Лоуренса (LLNL) в качестве сопровождающего. [8] : 10 Другими ранними участниками являются Дэвид Эшер, Конрад Хинсен и Трэвис Олифант . [8] : 10
Новый пакет под названием Numarray был написан как более гибкая замена Numeric. [9] Как и Numeric, он также теперь устарел. [10] [11] Numarray имел более быстрые операции для больших массивов, но был медленнее, чем Numeric для маленьких, [12] поэтому некоторое время оба пакета использовались параллельно для разных вариантов использования. Последняя версия Numeric (v24.2) была выпущена 11 ноября 2005 года, в то время как последняя версия numarray (v1.5.2) была выпущена 24 августа 2006 года. [13]
Было желание включить Numeric в стандартную библиотеку Python, но Гвидо ван Россум решил, что код в его нынешнем состоянии не поддается поддержке. [ когда? ] [14]
В начале 2005 года разработчик NumPy Трэвис Олифант захотел объединить сообщество вокруг одного пакета массивов и перенес функции Numarray в Numeric, выпустив результат как NumPy 1.0 в 2006 году. [9] Этот новый проект был частью SciPy . Чтобы избежать установки большого пакета SciPy только для получения объекта массива, этот новый пакет был отделен и назван NumPy. Поддержка Python 3 была добавлена в 2011 году с версией NumPy 1.5.0. [15]
В 2011 году PyPy начал разработку реализации API NumPy для PyPy. [16] По состоянию на 2023 год он еще не полностью совместим с NumPy. [17]
NumPy нацелен на эталонную реализацию CPython Python, которая является неоптимизирующим интерпретатором байт-кода . Математические алгоритмы, написанные для этой версии Python, часто работают намного медленнее, чем скомпилированные эквиваленты из-за отсутствия оптимизации компилятора. NumPy решает проблему медленности частично, предоставляя многомерные массивы, а также функции и операторы, которые эффективно работают с массивами; их использование требует переписывания некоторого кода, в основном внутренних циклов , с использованием NumPy.
Использование NumPy в Python дает функциональность, сравнимую с MATLAB , поскольку они оба интерпретируются, [18] и они оба позволяют пользователю писать быстрые программы, пока большинство операций работают с массивами или матрицами вместо скаляров . Для сравнения, MATLAB может похвастаться большим количеством дополнительных наборов инструментов, в частности Simulink , тогда как NumPy внутренне интегрирован с Python, более современным и полным языком программирования . Более того, доступны дополнительные пакеты Python; SciPy — это библиотека, которая добавляет больше функциональности, подобной MATLAB, а Matplotlib — это пакет для построения графиков , который обеспечивает функциональность построения графиков, подобную MATLAB. Хотя Matlab может выполнять операции с разреженными матрицами, numpy сам по себе не может выполнять такие операции и требует использования библиотеки scipy.sparse. Внутренне и MATLAB, и NumPy полагаются на BLAS и LAPACK для эффективных вычислений линейной алгебры .
Связывания Python широко используемой библиотеки компьютерного зрения OpenCV используют массивы NumPy для хранения и работы с данными. Поскольку изображения с несколькими каналами просто представлены в виде трехмерных массивов, индексирование, нарезка или маскирование с другими массивами являются очень эффективными способами доступа к определенным пикселям изображения. Массив NumPy как универсальная структура данных в OpenCV для изображений, извлеченных точек объектов , ядер фильтров и многого другого значительно упрощает рабочий процесс программирования и отладки . [ требуется цитата ]
Важно отметить, что многие операции NumPy снимают глобальную блокировку интерпретатора , что позволяет выполнять многопоточную обработку. [19]
NumPy также предоставляет API C, который позволяет коду Python взаимодействовать с внешними библиотеками, написанными на языках низкого уровня. [20]
Основная функциональность NumPy — это его "ndarray", n -мерный массив, структура данных . Эти массивы являются пошаговыми представлениями в памяти. [9] В отличие от встроенной структуры данных списка Python, эти массивы однородно типизированы: все элементы одного массива должны быть одного типа.
Такие массивы также могут быть представлениями в буферах памяти, выделенных расширениями C / C++ , Python и Fortran для интерпретатора CPython без необходимости копирования данных, что обеспечивает определенную степень совместимости с существующими числовыми библиотеками. Эта функциональность используется пакетом SciPy, который оборачивает ряд таких библиотек (в частности, BLAS и LAPACK). NumPy имеет встроенную поддержку отображенных в память ndarrays. [9]
Вставка или добавление записей в массив не так тривиально возможно, как в списках Python. np.pad(...)
Процедура расширения массивов фактически создает новые массивы желаемой формы и значений заполнения, копирует заданный массив в новый и возвращает его. np.concatenate([a1,a2])
Операция NumPy фактически не связывает два массива, а возвращает новый, заполненный записями из обоих заданных массивов последовательно. Изменение размерности массива с помощью np.reshape(...)
возможно только до тех пор, пока количество элементов в массиве не изменится. Эти обстоятельства возникают из-за того, что массивы NumPy должны быть представлениями в смежных буферах памяти .
Алгоритмы , которые не могут быть выражены как векторизованные операции, обычно будут работать медленно, поскольку они должны быть реализованы на «чистом Python», в то время как векторизация может увеличить сложность памяти некоторых операций с константы до линейной, поскольку должны быть созданы временные массивы, которые имеют такой же размер, как и входные данные. Компиляция числового кода во время выполнения была реализована несколькими группами, чтобы избежать этих проблем; решения с открытым исходным кодом, которые взаимодействуют с NumPy, включают numexpr [21] и Numba . [22] Cython и Pythran являются альтернативами им со статической компиляцией.
Многие современные крупномасштабные научные вычислительные приложения имеют требования, которые превышают возможности массивов NumPy. Например, массивы NumPy обычно загружаются в память компьютера , которая может иметь недостаточную емкость для анализа больших наборов данных . Кроме того, операции NumPy выполняются на одном ЦП . Однако многие операции линейной алгебры можно ускорить, выполняя их на кластерах ЦП или специализированном оборудовании, таком как графические процессоры и TPU , на которое опираются многие приложения глубокого обучения . В результате за последние годы в научной экосистеме Python появилось несколько альтернативных реализаций массивов, таких как Dask для распределенных массивов и TensorFlow или JAX для вычислений на графических процессорах. Из-за своей популярности они часто реализуют подмножество API NumPy или имитируют его, так что пользователи могут изменять свою реализацию массива с минимальными изменениями в требуемом коде. [3] Библиотека CuPy , [23] ускоренная фреймворком CUDA от Nvidia , также продемонстрировала потенциал для более быстрых вычислений, являясь « прямой заменой » NumPy. [24]
импорт numpy как np из numpy.random импорт rand из numpy.linalg импорт resolve , inv a = np.array ( [ [ 1,2,3,4 ] , [ 3,4,6,7 ] , [ 5,9,0,5 ] ] ) a.transpose ( )
>>> a = np.array ( [ 1,2,3,6 ] ) >>> b = np.linspace ( 0,2,4 ) # создаем массив с четырьмя равноотстоящими точками , начиная с 0 и заканчивая 2. >>> c = a - b >>> c array ( [ 1. , 1.33333333,1.66666667,4 . ] ) >>> a ** 2 array ( [ 1,4,9,36 ] )
>>> a = np . linspace ( - np . pi , np . pi , 100 ) >>> b = np . sin ( a ) >>> c = np . cos ( a ) >>> >>> # Функции могут принимать в качестве параметров как числа, так и массивы. >>> np . sin ( 1 ) 0.8414709848078965 >>> np . sin ( np . array ([ 1 , 2 , 3 ])) array ([ 0.84147098 , 0.90929743 , 0.14112001 ])
>>> из numpy.random импорт rand >>> из numpy.linalg импорт resolve , inv >>> a = np . array ([[ 1 , 2 , 3 ], [ 3 , 4 , 6.7 ], [ 5 , 9.0 , 5 ]]) >>> a . transpose () array ([[ 1. , 3. , 5. ], [ 2. , 4. , 9. ], [ 3. , 6.7 , 5. ]]) >>> inv ( a ) array ([[ - 2.27683616 , 0.96045198 , 0.07909605 ], [ 1.04519774 , - 0.56497175 , 0.1299435 ], [ 0.39548023 , 0.05649718 , - 0.11299435 ]]) >>> b = np . array ([ 3,2,1 ] ) >>> resolve ( a , b ) # решить уравнение ax = b array ( [ -4,83050847,2,13559322,1,18644068 ] ) >>> c = rand ( 3,3 ) * 20 # создать случайную матрицу 3x3 значений в диапазоне [ 0,1 ] , масштабированную на 20 >>> c array ( [ [ 3,98732789,2,47702609,4,71167924 ] , [ 9,24410671,5,5240412,10,6468792 ] , [ 10,38136661,8,44968437 , 15.17639591 ]]) >>> np . dot ( a , c ) # массив умножения матриц ([[ 53.61964114 , 38.8741616 , 71.53462537 ], [ 118.4935668 , 86.14012835 , 158.40440712 ], [ 155.04043289 , 104.3499231 , 195.26228855 ]]) >>> a @ c # Начиная с Python 3.5 и NumPy 1.10 array ([[ 53.61964114 , 38.8741616 , 71.53462537 ], [ 118.4935668 , 86.14012835 , 158.40440712 ], [ 155.04043289 , 104.3499231 , 195.26228855 ]])
>>> M = np . нули ( форма = ( 2 , 3 , 5 , 7 , 11 )) >>> T = np . транспонировать ( M , ( 4 , 2 , 1 , 3 , 0 )) >>> T . форма ( 11 , 5 , 3 , 7 , 2 )
>>> import numpy as np >>> import cv2 >>> r = np . reshape ( np . arange ( 256 * 256 ) % 256 , ( 256 , 256 )) # Массив 256x256 пикселей с горизонтальным градиентом от 0 до 255 для канала красного цвета >>> g = np . zeros_like ( r ) # Массив того же размера и типа, что и r, но заполнен нулями для канала зеленого цвета >>> b = r . T # транспонированный r даст вертикальный градиент для канала синего цвета >>> cv2 . imwrite ( 'gradients.png ' , np . dstack ( [ b , g , r ])) # Изображения OpenCV интерпретируются как BGR, массив с глубиной стека будет записан в 8-битный RGB PNG-файл с именем 'gradients.png' True
Итеративный алгоритм Python и векторизованная версия NumPy.
>>> # # # Чистый итеративный Python # # # >>> points = [[ 9 , 2 , 8 ],[ 4 , 7 , 2 ],[ 3 , 4 , 4 ],[ 5 , 6 , 9 ],[ 5 , 0 , 7 ],[ 8 , 2 , 7 ],[ 0 , 3 , 2 ],[ 7 , 3 , 0 ],[ 6 , 1 , 1 ],[ 2 , 9 , 6 ]] >>> qPoint = [ 4 , 5 , 3 ] >>> minIdx = - 1 >>> minDist = - 1 >>> for idx , point in enumerate ( points ): # итерация по всем точкам ... dist = sum ([( dp - dq ) ** 2 for dp , dq in zip ( point , qPoint )]) ** 0.5 # вычислить евклидово расстояние для каждой точки до q ... if dist < minDist или minDist < 0 : # при необходимости обновить минимальное расстояние и индекс соответствующей точки ... minDist = dist ... minIdx = idx>>> print ( f 'Ближайшая точка к q: { points [ minIdx ] } ' ) Ближайшая точка к q : [ 3 , 4 , 4 ]>>> # # # Эквивалентная векторизация NumPy # # # >>> импорт numpy как np >>> points = np . array ([[ 9 , 2 , 8 ],[ 4 , 7 , 2 ],[ 3 , 4 , 4 ],[ 5 , 6 , 9 ],[ 5 , 0 , 7 ],[ 8 , 2 , 7 ],[ 0 , 3 , 2 ],[ 7 , 3 , 0 ],[ 6 , 1 , 1 ],[ 2 , 9 , 6 ]]) >>> qPoint = np . array ([ 4 , 5 , 3 ]) >>> minIdx = np . argmin ( np . linalg . norm ( points - qPoint , axis = 1 )) # вычислить все евклидовы расстояния одновременно и вернуть индекс наименьшего из них >>> print ( f 'Ближайшая точка к q: { points [ minIdx ] } ' ) Ближайшая точка к q : [ 3 4 4 ]
Быстрое создание оболочки для собственного кода для более быстрых скриптов. [25] [26] [27]
! Пример вызова собственного кода Python Fortran ! f2py -c -m foo *.f90 ! Компилирование Fortran в именованный модуль python с использованием операторов намерения ! Только подпрограммы Fortran, а не функции — проще, чем JNI с оболочкой C ! Требуется gfortran и make subroutine ftest ( a , b , n , c , d ) implicit none integer , intent ( in ) :: a , b , n integer , intent ( out ) :: c , d integer :: i c = 0 do i = 1 , n c = a + b + c end do d = ( c * n ) * ( - 1 ) end subroutine ftest
>>> import numpy as np >>> import foo >>> a = foo.ftest ( 1,2,3 ) # или c,d = вместо ac и ad >>> print ( a ) ( 9 , -27) >>> help( ' foo.ftest ' ) # foo.ftest .__ doc__