NumPy (pronunciado /ˈnʌmpaɪ/ NUM - py ) es una biblioteca para el lenguaje de programación Python , que agrega soporte para matrices y arreglos multidimensionales grandes , junto con una gran colección de funciones matemáticas de alto nivel para operar en estos arreglos. [3] El predecesor de NumPy, Numeric, fue creado originalmente por Jim Hugunin con contribuciones de varios otros desarrolladores. En 2005, Travis Oliphant creó NumPy incorporando características del competidor Numarray en Numeric, con amplias modificaciones. NumPy es un software de código abierto y tiene muchos contribuyentes. NumPy es un proyecto patrocinado fiscalmente por NumFOCUS. [4]
El lenguaje de programación Python no fue diseñado originalmente para el cálculo numérico, pero atrajo la atención de la comunidad científica y de ingeniería desde el principio. En 1995 se fundó el grupo de interés especial (SIG) matrix-sig con el objetivo de definir un paquete de computación de matrices ; entre sus miembros se encontraba el diseñador y mantenedor de Python Guido van Rossum , quien extendió la sintaxis de Python (en particular la sintaxis de indexación [5] ) para facilitar la computación de matrices . [6]
Jim Fulton completó una implementación de un paquete de matrices, que luego fue generalizado [ se necesita más explicación ] por Jim Hugunin y llamado Numeric [6] (también conocido como las "extensiones numéricas de Python" o "NumPy"), con influencias de la familia de lenguajes APL , Basis, MATLAB , FORTRAN , S y S+ , y otros. [7] [8] Hugunin, un estudiante de posgrado en el Instituto Tecnológico de Massachusetts (MIT), [8] : 10 se unió a la Corporación para Iniciativas Nacionales de Investigación (CNRI) en 1997 para trabajar en JPython , [6] dejando a Paul Dubois del Laboratorio Nacional Lawrence Livermore (LLNL) para que asumiera el cargo de mantenedor. [8] : 10 Otros contribuyentes tempranos incluyen a David Ascher, Konrad Hinsen y Travis Oliphant . [8] : 10
Se escribió un nuevo paquete llamado Numarray como reemplazo más flexible de Numeric. [9] Al igual que Numeric, también está en desuso. [10] [11] Numarray tenía operaciones más rápidas para matrices grandes, pero era más lento que Numeric en matrices pequeñas, [12] por lo que durante un tiempo ambos paquetes se usaron en paralelo para diferentes casos de uso. La última versión de Numeric (v24.2) se lanzó el 11 de noviembre de 2005, mientras que la última versión de numarray (v1.5.2) se lanzó el 24 de agosto de 2006. [13]
Existía el deseo de incluir Numeric en la biblioteca estándar de Python, pero Guido van Rossum decidió que el código no era mantenible en su estado en ese momento. [ ¿cuándo? ] [14]
A principios de 2005, el desarrollador de NumPy, Travis Oliphant, quiso unificar la comunidad en torno a un único paquete de matrices y trasladó las características de Numarray a Numeric, publicando el resultado como NumPy 1.0 en 2006. [9] Este nuevo proyecto formaba parte de SciPy . Para evitar instalar el gran paquete SciPy solo para obtener un objeto de matriz, este nuevo paquete se separó y se denominó NumPy. La compatibilidad con Python 3 se agregó en 2011 con la versión 1.5.0 de NumPy. [15]
En 2011, PyPy comenzó a desarrollar una implementación de la API NumPy para PyPy. [16] A partir de 2023, todavía no es totalmente compatible con NumPy. [17]
NumPy apunta a la implementación de referencia CPython de Python, que es un intérprete de bytecode no optimizador . Los algoritmos matemáticos escritos para esta versión de Python suelen ejecutarse mucho más lento que sus equivalentes compilados debido a la ausencia de optimización del compilador. NumPy aborda el problema de la lentitud en parte al proporcionar matrices multidimensionales y funciones y operadores que operan de manera eficiente en matrices; su uso requiere reescribir parte del código, principalmente bucles internos , utilizando NumPy.
El uso de NumPy en Python proporciona una funcionalidad comparable a MATLAB , ya que ambos son interpretados [18] y ambos permiten al usuario escribir programas rápidos siempre que la mayoría de las operaciones funcionen en arreglos o matrices en lugar de escalares . En comparación, MATLAB cuenta con una gran cantidad de cajas de herramientas adicionales, en particular Simulink , mientras que NumPy está intrínsecamente integrado con Python, un lenguaje de programación más moderno y completo . Además, hay paquetes complementarios de Python disponibles; SciPy es una biblioteca que agrega más funcionalidad similar a MATLAB y Matplotlib es un paquete de gráficos que proporciona una funcionalidad de gráficos similar a MATLAB. Aunque Matlab puede realizar operaciones de matriz dispersa, Numpy por sí solo no puede realizar tales operaciones y requiere el uso de la biblioteca scipy.sparse. Internamente, tanto MATLAB como NumPy dependen de BLAS y LAPACK para realizar cálculos de álgebra lineal eficientes .
Los enlaces de Python de la biblioteca de visión artificial OpenCV, ampliamente utilizada , utilizan matrices NumPy para almacenar y operar con datos. Dado que las imágenes con múltiples canales se representan simplemente como matrices tridimensionales, la indexación, el corte o el enmascaramiento con otras matrices son formas muy eficientes de acceder a píxeles específicos de una imagen. La matriz NumPy como estructura de datos universal en OpenCV para imágenes, puntos característicos extraídos , núcleos de filtro y mucho más simplifica enormemente el flujo de trabajo de programación y depuración . [ cita requerida ]
Es importante destacar que muchas operaciones de NumPy liberan el bloqueo del intérprete global , lo que permite el procesamiento multiproceso. [19]
NumPy también proporciona una API C, que permite que el código Python interopere con bibliotecas externas escritas en lenguajes de bajo nivel. [20]
La funcionalidad principal de NumPy es su estructura de datos "ndarray", para matrices n -dimensionales . Estas matrices son vistas escalonadas en la memoria. [9] A diferencia de la estructura de datos de lista incorporada de Python, estas matrices tienen tipos homogéneos: todos los elementos de una sola matriz deben ser del mismo tipo.
Estas matrices también pueden visualizarse en búferes de memoria asignados por extensiones de C / C++ , Python y Fortran al intérprete CPython sin necesidad de copiar datos, lo que proporciona un grado de compatibilidad con las bibliotecas numéricas existentes. Esta funcionalidad es explotada por el paquete SciPy, que encapsula varias de estas bibliotecas (especialmente BLAS y LAPACK). NumPy tiene soporte integrado para ndarrays mapeados en memoria . [9]
Insertar o agregar entradas a una matriz no es tan trivialmente posible como lo es con las listas de Python. La np.pad(...)
rutina para extender matrices en realidad crea nuevas matrices de la forma deseada y los valores de relleno, copia la matriz dada en la nueva y la devuelve. np.concatenate([a1,a2])
La operación de NumPy en realidad no vincula las dos matrices, sino que devuelve una nueva, llena con las entradas de ambas matrices dadas en secuencia. Reformar la dimensionalidad de una matriz con np.reshape(...)
solo es posible mientras el número de elementos en la matriz no cambie. Estas circunstancias se originan del hecho de que las matrices de NumPy deben ser vistas en búferes de memoria contiguos .
Los algoritmos que no se pueden expresar como una operación vectorizada normalmente se ejecutarán lentamente porque deben implementarse en "Python puro", mientras que la vectorización puede aumentar la complejidad de la memoria de algunas operaciones de constante a lineal, porque se deben crear matrices temporales que sean tan grandes como las entradas. Varios grupos han implementado la compilación en tiempo de ejecución de código numérico para evitar estos problemas; las soluciones de código abierto que interoperan con NumPy incluyen numexpr [21] y Numba . [22] Cython y Pythran son alternativas de compilación estática a estas.
Muchas aplicaciones informáticas científicas modernas a gran escala tienen requisitos que exceden las capacidades de las matrices NumPy. Por ejemplo, las matrices NumPy generalmente se cargan en la memoria de una computadora , que puede tener capacidad insuficiente para el análisis de grandes conjuntos de datos . Además, las operaciones NumPy se ejecutan en una sola CPU . Sin embargo, muchas operaciones de álgebra lineal se pueden acelerar al ejecutarlas en grupos de CPU o de hardware especializado, como GPU y TPU , de los que dependen muchas aplicaciones de aprendizaje profundo . Como resultado, han surgido varias implementaciones de matrices alternativas en el ecosistema científico de Python en los últimos años, como Dask para matrices distribuidas y TensorFlow o JAX para cálculos en GPU. Debido a su popularidad, estos a menudo implementan un subconjunto de la API de NumPy o lo imitan, de modo que los usuarios pueden cambiar la implementación de su matriz con cambios mínimos en su código requerido. [3] Una biblioteca llamada CuPy , [23] acelerada por el marco CUDA de Nvidia , también ha demostrado potencial para una computación más rápida, siendo un " reemplazo directo " de NumPy. [24]
importar numpy como np desde numpy.random importar rand desde numpy.linalg importar solve , 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 ) # crea una matriz con cuatro puntos espaciados de manera uniforme comenzando con 0 y terminando con 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 ) >>> >>> # Las funciones pueden tomar números y matrices como parámetros. >>> np . sin ( 1 ) 0.8414709848078965 >>> np . sin ( np . array ([ 1 , 2 , 3 ])) array ([ 0.84147098 , 0.90929743 , 0.14112001 ])
>>> de numpy.random importe rand >>> de numpy.linalg importe solve , inv >>> a = np . array ([[ 1 , 2 , 3 ], [ 3 , 4 , 6.7 ], [ 5 , 9.0 , 5 ]]) >>> a . transpose () matriz ([[ 1 , 3 , 5 ], [ 2 , 4 , 9 ], [ 3 , 6,7 , 5 ]]) >>> inv ( a ) matriz ([[ -2,27683616 , 0,96045198 , 0,07909605 ], [ 1,04519774 , -0,56497175 , 0,1299435 ] , [ 0,39548023 , 0,05649718 , -0,11299435 ] ] ) >>> b = np . array ([ 3 , 2 , 1 ]) >>> solve ( a , b ) # resuelve la ecuación ax = b array ([ - 4.83050847 , 2.13559322 , 1.18644068 ]) >>> c = rand ( 3 , 3 ) * 20 # crea una matriz aleatoria de 3x3 de valores dentro de [0,1] escalada por 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 ) # matriz de multiplicación ( [[ 53.61964114 , 38.8741616 , 71.53462537 ], [ 118.4935668 , 86.14012835 , 158.40440712 ], [ 155.04043289 , 104.3499231 , 195.26228855 ]]) >>> a @ c # A partir de Python 3.5 y NumPy 1.10 array ([[ 53.61964114 , 38.8741616 , 71.53462537 ], [ 118.4935668 , 86.14012835 , 158.40440712 ], [ 155.04043289 , 104.3499231 , 195.26228855 ]])
>>> M = np . ceros ( forma = ( 2 , 3 , 5 , 7 , 11 )) >>> T = np . transponer ( M , ( 4 , 2 , 1 , 3 , 0 )) >>> T . forma ( 11 , 5 , 3 , 7 , 2 )
>>> import numpy as np >>> import cv2 >>> r = np . reshape ( np . arange ( 256 * 256 ) % 256 ,( 256 , 256 )) # Matriz de 256x256 píxeles con un gradiente horizontal de 0 a 255 para el canal de color rojo >>> g = np . zeros_like ( r ) # Matriz del mismo tamaño y tipo que r pero llena de 0 para el canal de color verde >>> b = r . T # r transpuesto dará un gradiente vertical para el canal de color azul >>> cv2 . imwrite ( 'gradients.png' , np . dstack ([ b , g , r ])) # Las imágenes OpenCV se interpretan como BGR, la matriz apilada en profundidad se escribirá en un archivo PNG RGB de 8 bits llamado 'gradients.png' True
Algoritmo iterativo de Python y versión vectorizada de NumPy.
>>> # # # Python iterativo puro # # # >>> puntos = [[ 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 ]] >>> qPunto = [ 4 , 5 , 3 ] >>> minIdx = - 1 >>> minDist = - 1 >>> para idx , punto en enumerate ( puntos ): # iterar sobre todos los puntos ... dist = suma ([( dp - dq ) ** 2 para dp , dq en zip ( punto , qPoint )]) ** 0.5 # calcula la distancia euclidiana de cada punto a q ... si dist < minDist o minDist < 0 : # si es necesario, actualiza la distancia mínima y el índice del punto correspondiente ... minDist = dist ... minIdx = idx>>> print ( f 'Punto más cercano a q: { puntos [ minIdx ] } ' ) Punto más cercano a q : [ 3 , 4 , 4 ] >>> # # # Vectorización NumPy equivalente # # # >>> import numpy as 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 )) # calcula todas las distancias euclidianas a la vez y devuelve el índice de la más pequeña >>> print ( f ' Punto más cercano a q: { points [ minIdx ] } ' ) Punto más cercano a q : [ 3 4 4 ]
Envuelva rápidamente el código nativo para crear scripts más rápidos. [25] [26] [27]
! Ejemplo de llamada de código nativo de Python Fortran ! f2py -c -m foo *.f90 ! Compila Fortran en un módulo nombrado de Python usando declaraciones intent ! Subrutinas Fortran solamente, no funciones; más fácil que JNI con contenedor C ! requiere gfortran y make subrutine ftest ( a , b , n , c , d ) implicit none whole , intent ( in ) :: a , b , n whole , intent ( out ) :: c , d whole :: i c = 0 do i = 1 , n c = a + b + c end do d = ( c * n ) * ( - 1 ) end subrutine ftest
>>> import numpy como np >>> import foo >>> a = foo . ftest ( 1 , 2 , 3 ) # o c,d = en lugar de ac y ad >>> print ( a ) (9,-27) >>> help ( 'foo.ftest' ) # foo.ftest.__doc__