Qué es NumPy
NumPy (Numerical Python) es la biblioteca fundamental para el cálculo numérico en Python. Proporciona una estructura de datos llamada ndarray que permite almacenar y manipular grandes volúmenes de datos numéricos de forma eficiente. Prácticamente toda la computación científica en Python se apoya en NumPy como capa base.
La NumPy 2.x supone un salto importante en la línea estable: API más ordenada, mejor rendimiento en copias y alineación del tipo entero por defecto en Windows con el resto de plataformas 64 bits. Los ejemplos del curso siguen las prácticas recomendadas para NumPy 2.x (por ejemplo numpy.random.Generator vía default_rng).
A diferencia de las listas nativas de Python, un ndarray almacena todos sus elementos de forma contigua en memoria y con un tipo de dato homogéneo. Esto permite que las operaciones se ejecuten en código compilado en lugar de iterar elemento a elemento con el intérprete de Python.
La documentación de referencia del proyecto está en numpy.org.
import numpy as np
# Crear un ndarray a partir de una lista
temperaturas = np.array([22.5, 23.1, 19.8, 25.3, 21.0])
print(type(temperaturas)) # <class 'numpy.ndarray'>
print(temperaturas.dtype) # float64
print(temperaturas.shape) # (5,)
El ndarray es la piedra angular de NumPy. Todos los datos se representan como arrays n-dimensionales con un tipo de dato fijo, lo que permite optimizaciones internas que las listas de Python no pueden ofrecer.
NumPy en el ecosistema científico de Python
NumPy no trabaja de forma aislada. Es la base sobre la que se construyen las bibliotecas más utilizadas en ciencia de datos, machine learning y visualización. La relación entre estas bibliotecas sigue una jerarquía clara.
flowchart TD
NP[NumPy<br>ndarray y cálculo numérico]
PD[Pandas<br>DataFrames y Series]
SK[Scikit-learn<br>Machine Learning]
MP[Matplotlib<br>Visualización]
NP --> PD
NP --> SK
NP --> MP
PD --> SK
PD --> MP
Pandas utiliza arrays de NumPy como almacenamiento interno de sus Series y DataFrames. Cuando se extrae una columna numérica de un DataFrame con .values o .to_numpy(), se obtiene un ndarray de NumPy.
Scikit-learn espera que los datos de entrada sean arrays de NumPy o estructuras compatibles. Los métodos fit() y predict() trabajan internamente con ndarrays para realizar los cálculos de los modelos.
Matplotlib acepta arrays de NumPy como entrada directa para generar gráficos. Las funciones de trazado como plt.plot() o plt.scatter() procesan ndarrays de forma nativa.
import numpy as np
import pandas as pd
# Pandas usa NumPy internamente
df = pd.DataFrame({"precio": [10.5, 20.3, 15.7]})
array_precios = df["precio"].to_numpy()
print(type(array_precios)) # <class 'numpy.ndarray'>
Esta integración significa que aprender NumPy no es opcional: es un requisito para trabajar con cualquier herramienta del ecosistema científico de Python.
Concepto de ndarray
El ndarray (n-dimensional array) es un contenedor de datos con las siguientes características:
- Homogeneidad: todos los elementos tienen el mismo tipo de dato (
int64,float64,bool, etc.) - Forma fija: la estructura se define por una tupla de dimensiones (shape)
- Almacenamiento contiguo: los datos se guardan en un bloque continuo de memoria
Estas propiedades permiten que NumPy delegue las operaciones a rutinas escritas en C y Fortran, eliminando la sobrecarga del intérprete de Python.
import numpy as np
# Array 1D: vector de 4 elementos
vector = np.array([1, 2, 3, 4])
print(vector.ndim) # 1
print(vector.shape) # (4,)
# Array 2D: matriz de 2 filas y 3 columnas
matriz = np.array([[1, 2, 3],
[4, 5, 6]])
print(matriz.ndim) # 2
print(matriz.shape) # (2, 3)
# Array 3D: cubo de datos
cubo = np.array([[[1, 2], [3, 4]],
[[5, 6], [7, 8]]])
print(cubo.ndim) # 3
print(cubo.shape) # (2, 2, 2)
Cada ndarray expone atributos clave como dtype (tipo de dato), size (número total de elementos), nbytes (memoria ocupada) e itemsize (bytes por elemento). Estos atributos facilitan el control del consumo de memoria en aplicaciones con grandes volúmenes de datos.
Operaciones vectorizadas
Una operación vectorizada es aquella que se aplica a todos los elementos de un array de forma simultánea, sin necesidad de escribir un bucle explícito. Esta es la forma idiomática de trabajar con NumPy y la principal fuente de rendimiento.
import numpy as np
precios = np.array([100, 200, 150, 300, 250])
# Aplicar un descuento del 15% de forma vectorizada
precios_descuento = precios * 0.85
print(precios_descuento) # [ 85. 170. 127.5 255. 212.5]
# Calcular el IVA (21%) sobre cada precio
iva = precios * 0.21
print(iva) # [21. 42. 31.5 63. 52.5]
Las operaciones aritméticas (+, -, *, /, **), las comparaciones (>, <, ==) y las funciones matemáticas (np.sqrt, np.log, np.sin) se aplican elemento a elemento de forma automática. Esto elimina la necesidad de list comprehensions o bucles for.
import numpy as np
notas = np.array([4.5, 7.2, 8.9, 3.1, 6.0])
# Comparacion vectorizada
aprobados = notas >= 5.0
print(aprobados) # [False True True False True]
# Filtrado con máscara booleana
notas_aprobadas = notas[aprobados]
print(notas_aprobadas) # [7.2 8.9 6. ]
Las operaciones vectorizadas no son solo una cuestión de sintaxis limpia. Internamente, NumPy ejecuta las operaciones en código C optimizado, lo que produce mejoras de rendimiento de uno o dos órdenes de magnitud frente al equivalente con bucles de Python.
Rendimiento: NumPy frente a listas de Python
La diferencia de rendimiento entre un ndarray de NumPy y una lista nativa de Python es considerable. El siguiente benchmark compara ambas estructuras en una operación habitual: multiplicar cada elemento por un escalar.
import numpy as np
import time
n = 1_000_000
# Benchmark con lista de Python
lista = list(range(n))
inicio = time.perf_counter()
resultado_lista = [x * 2 for x in lista]
tiempo_lista = time.perf_counter() - inicio
# Benchmark con array de NumPy
array = np.arange(n)
inicio = time.perf_counter()
resultado_array = array * 2
tiempo_array = time.perf_counter() - inicio
print(f"Lista Python: {tiempo_lista:.4f} s")
print(f"Array NumPy: {tiempo_array:.4f} s")
print(f"NumPy es {tiempo_lista / tiempo_array:.1f}x mas rapido")
En una ejecución típica, el resultado muestra que NumPy es entre 20x y 100x más rápido que la lista de Python para esta operación. La diferencia se amplifica con operaciones más complejas y volúmenes de datos mayores.
Las razones de esta ventaja son tres:
- Memoria contigua: el ndarray almacena los datos en un bloque continuo, lo que aprovecha la cache del procesador.
- Código compilado: las operaciones se ejecutan en C, no en el intérprete de Python.
- Ausencia de comprobaciones de tipo: al ser homogéneo, NumPy no necesita verificar el tipo de cada elemento en cada operación.
import numpy as np
import time
n = 500_000
# Suma de dos colecciones: lista vs array
lista_a = list(range(n))
lista_b = list(range(n))
inicio = time.perf_counter()
suma_lista = [a + b for a, b in zip(lista_a, lista_b)]
tiempo_lista = time.perf_counter() - inicio
array_a = np.arange(n)
array_b = np.arange(n)
inicio = time.perf_counter()
suma_array = array_a + array_b
tiempo_array = time.perf_counter() - inicio
print(f"Suma listas: {tiempo_lista:.4f} s")
print(f"Suma arrays: {tiempo_array:.4f} s")
Este patrón se repite en cualquier operación numérica. Por ello, cuando se trabaja con datos numéricos en Python, utilizar listas nativas en lugar de arrays de NumPy supone un coste de rendimiento innecesario.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, NumPy es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de NumPy
Explora más contenido relacionado con NumPy y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Comprender qué es NumPy, su papel en el ecosistema científico de Python, el concepto de ndarray, las operaciones vectorizadas y las ventajas de rendimiento frente a listas nativas.
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje