Saltar al contenido principal
ActivePapers Almacena tus datos como documentos recomputables para que cualquier resultado publicado pueda ejecutarse de nuevo, verificarse y preservarse.

Algunos enlaces de este sitio son de afiliados: si compras a través de ellos, es posible que recibamos una comisión sin coste adicional para ti. Esto nunca afecta a nuestras recomendaciones. Consulta nuestra declaración de afiliados para más detalles. Divulgación de afiliados.

Procesamiento de datos NumPy: una guía práctica

El procesamiento de datos con NumPy es la práctica de cargar, remodelar, limpiar y reducir matrices numéricas con la biblioteca NumPy, cuyo objeto central ndarray almacena datos homogéneos en un bloque de memoria contiguo de tamaño fijo. Desde su lanzamiento en 2006, NumPy se ha convertido en el sustrato de SciPy, pandas, scikit-learn y de la mayor parte del ecosistema científico de Python, por lo que los hábitos que desarrolle aquí se propagarán a todas partes.

Conclusiones clave

  • El ndarray es una vista con zancadas (strided view) sobre un búfer de memoria plano; comprender las zancadas explica por qué reshape, el slicing y transpose son económicos, mientras que copy y la indexación sofisticada (fancy indexing) no lo son.
  • La vectorización no es meramente estilística: traslada el bucle desde Python interpretado a C compilado, y la aceleración suele ser de uno a dos órdenes de magnitud para trabajos con carga aritmética intensa.
  • La disposición de la memoria (orden C vs F) y la elección del dtype a menudo importan más que la elección del algoritmo para matrices de simulación grandes; una matriz float64 de 10^8 elementos ya consume 800 MB antes de realizar cualquier copia.
  • Para matrices que no caben en la RAM, numpy.memmap y el acceso respaldado por HDF5 (h5py) permiten procesar en fragmentos (chunks) sin tener que reescribir el código de análisis para el procesamiento de datos con NumPy.
  • La reproducibilidad depende de controlar el RNG explícitamente (np.random.default_rng(seed)), fijar las versiones y registrar el dtype y la forma junto con los resultados.

Qué es realmente NumPy (y por qué es importante para el procesamiento)

La abstracción central de NumPy es una matriz multidimensional tipada con una forma (shape), un dtype y un conjunto de zancadas (strides) que describen cuántos bytes saltar para llegar al siguiente elemento a lo largo de cada eje. Esa decisión de diseño —separar la forma lógica de la disposición física— es lo que hace que NumPy sea rápido y flexible.

Una matriz float64 de (1000, 1000) ocupa 8 MB de memoria contigua; transponerla no mueve ni un solo byte, solo reescribe los metadatos de la zancada. El slicing se comporta de la misma manera: a[::2] devuelve una vista, no una copia.

La implicación práctica para el procesamiento de datos con NumPy es que necesita saber cuándo tiene una vista y cuándo tiene una copia de la misma. Las vistas son económicas y comparten memoria, por lo que mutar una muta la original.

Las copias son seguras pero duplican su memoria máxima. La propia documentación de NumPy sobre vistas y copias de matrices es la referencia autorizada, y vale la pena leerla detenidamente una vez en lugar de depurar un error de aliasing silencioso más adelante.

Los dtypes merecen la misma atención. La salida de las simulaciones suele llegar como float64 por defecto, pero una trayectoria de dinámica molecular de coordenadas atómicas rara vez necesita más que float32 para la visualización, y los recuentos de enteros (índices de átomos, números de cuadros) deben ser int32 o int64 en lugar de float. Reducir a la mitad el dtype reduce a la mitad el tráfico de memoria, que para operaciones limitadas por el ancho de banda de memoria suele ser el coste dominante.

Relacionado: — Cursos interactivos de Python y ciencia de datos que codifica directamente en el navegador.

El flujo de trabajo principal de procesamiento de datos

Un flujo de trabajo típico de procesamiento de datos con NumPy para trabajos científicos tiene cinco pasos: ingestión, inspección, limpieza, transformación y reducción. Cada paso tiene herramientas idiomáticas de NumPy, y omitir el paso de inspección es la fuente más común de errores posteriores.

Ingestión. np.loadtxt y np.genfromtxt manejan texto plano, pero son lentos para archivos grandes porque analizan línea por línea en Python. np.load con .npy/.npz es la ruta binaria rápida. Para HDF5 —el estándar de facto en computación de alto rendimiento, mantenido por HDF Group— utilice h5py o PyTables, que exponen los conjuntos de datos como objetos similares a matrices que admiten lecturas parciales.

Inspección. Antes de cualquier operación aritmética, verifique arr.shape, arr.dtype y np.isnan(arr).any(). Un rápido arr.min(), arr.max() y arr.mean() revela errores de unidades y valores centinela (uno común es -9999, usado como marcador de datos faltantes en conjuntos de datos ambientales). Esta verificación de tres líneas encuentra más errores que cualquier conjunto de pruebas.

Vale la pena echarle un vistazo: — Una suscripción para certificados de ciencia de datos y Python respaldados por la universidad.

Limpieza. Los valores faltantes en NumPy se representan mediante np.nan para flotantes, y el NaN se propaga a través de la aritmética por diseño. Utilice np.nanmean, np.nanstd y np.nansum para ignorarlos, o np.isnan para enmascararlos explícitamente. Tenga en cuenta que las matrices de enteros no pueden contener NaN, un error común al leer datos CSV que contienen espacios en blanco.

Transformación. Aquí residen el remodelado (reshaping), el broadcasting y las operaciones por eje. arr.reshape(-1, 3) convierte un flujo de coordenadas plano en triples xyz; arr - arr.mean(axis=0) centra cada columna; np.einsum expresa contracciones tensoriales que de otro modo necesitarían bucles anidados.

Reducción. Agregación a lo largo de ejes con sum, mean, std, argmin y percentile. Para reducciones agrupadas, np.add.at o np.bincount manejan el caso en el que necesita acumular por índice en lugar de por bloque contiguo.

Vectorización, Broadcasting y el coste de los bucles

La vectorización consiste en expresar una operación sobre matrices completas para que NumPy la envíe a bucles compilados. El ejemplo canónico: calcular distancias por pares entre 10.000 puntos con un bucle doble de Python requiere del orden de 10^8 iteraciones interpretadas; la forma con broadcasting np.sqrt(((a[:, None, :] - b[None, :, :])**2).sum(-1)) hace el mismo trabajo en C, a costa de materializar una gran matriz intermedia.

Las reglas de broadcasting son el mecanismo que hace que esto sea conciso para el procesamiento de datos con NumPy. NumPy alinea las formas desde la derecha y expande las dimensiones de tamaño 1.

Una matriz (N, 3) menos una matriz (3,) resta el vector de cada fila. Una matriz (N, 1) multiplicada por una matriz (1, M) produce (N, M). Las reglas están documentadas en la guía de broadcasting de NumPy, y su internalización elimina la mayoría de los bucles for del código numérico.

Relacionado: — Una amplia biblioteca técnica de libros, vídeos y formación en directo sobre informática científica..

La contrapartida es la memoria. El broadcasting puede crear temporales mucho mayores que las entradas. Cuando esto se convierta en un cuello de botella, fragmente el cálculo o use np.einsum con optimize=True, lo que elimina algunos intermedios. Para problemas verdaderamente limitados por bucles que resisten la vectorización, el decorador @njit de Numba compila bucles de Python en código de máquina y es a menudo la vía de escape pragmática.

Comparación: elegir la herramienta adecuada para el trabajo

TareaNumPy idiomáticoCuándo buscar otra cosa
Cargar una trayectoria de 50 GBnp.memmap o lectura fragmentada h5pyDask o Zarr para acceso paralelo/en la nube
Agregación agrupada (group-by)np.bincount, np.add.atpandas groupby para datos etiquetados de tipo mixto
Distancias por paresBroadcasting + einsumSciPy cdist/pdist (optimizado para memoria)
Matrices dispersasnp.zeros (denso)SciPy sparse — lo denso desperdicia más del 90% de la memoria
Matemáticas personalizadas por elementoufuncs vectorizadosNumba o Cython cuando la lógica tiene muchas ramificaciones
Muestreo reproduciblenp.random.default_rng(seed)— (esta es la API moderna correcta)

El patrón para el procesamiento de datos con NumPy: NumPy es el valor predeterminado correcto, pero las matrices densas son la representación incorrecta para datos dispersos o etiquetados, y las matrices de una sola máquina son la representación incorrecta para datos fuera del núcleo (out-of-core).

Memoria, dtypes y procesamiento fuera del núcleo

La memoria suele ser la limitación vinculante en el trabajo científico con NumPy y en el procesamiento de datos, no la CPU. Tres técnicas responden a esto.

Favorito del lector: — Rutas de ciencia de datos basadas en proyectos con una terminal guiada y conjuntos de datos reales.

Primero, elija los dtypes deliberadamente. np.float32 reduce a la mitad la memoria en comparación con float64 y suele ser suficiente para resultados intermedios; np.int8 o np.uint16 cubren la mayoría de las matrices de índices y etiquetas. NumPy realizará upcasting silenciosamente en operaciones mixtas, así que verifique con arr.dtype después de la aritmética.

En segundo lugar, utilice matrices mapeadas en memoria. np.memmap mapea un archivo en disco al espacio de direcciones, lo que le permite hacer slicing de una matriz de 100 GB como si estuviera en RAM, con el sistema operativo paginando solo los bloques necesarios. Esto funciona bien para patrones de acceso secuencial y mal para el acceso aleatorio en toda la matriz.

En tercer lugar, procese en fragmentos. Leer un conjunto de datos HDF5 en bloques de, digamos, 10.000 filas y acumular una media móvil o un histograma mantiene limitada la memoria máxima independientemente del tamaño del archivo. Este es el patrón estándar en los flujos de bioinformática que transmiten lecturas de secuenciación y en los flujos de trabajo climáticos que reducen la producción de modelos de varias décadas.

Una sutileza: arr.copy() y la indexación sofisticada (arr[idx_array]) realizan asignaciones de memoria. En un bucle cerrado sobre fragmentos, estas asignaciones dominan el tiempo de ejecución. Reutilizar un búfer de salida preasignado con np.copyto o el argumento out= de las ufuncs evita este desgaste.

Reproducibilidad y procedencia

El trabajo numérico reproducible en el procesamiento de datos con NumPy requiere control sobre tres cosas que NumPy toca directamente: aleatoriedad, dtype y versión.

Aleatoriedad: se desaconseja el estado global heredado np.random.seed. La API moderna es rng = np.random.default_rng(seed), que devuelve un Generator aislado cuyo estado no se filtra entre funciones. Esto es importante cuando los trabajadores paralelos necesitan flujos independientes y reproducibles.

Dtype: registre el dtype de cada matriz que persista. Un resultado calculado en float32 y un resultado calculado en float64 difieren en los últimos dígitos, y los revisores que comparen resultados deben saber cuál se utilizó. Guardar con np.save conserva el dtype; guardar como CSV no lo hace.

Versión: el comportamiento de NumPy ha cambiado entre versiones de maneras que afectan los resultados; por ejemplo, el tipo de entero predeterminado en Windows y el manejo de ciertas reducciones. Fijar NumPy en su archivo de entorno y guardar la versión en los metadatos de salida es una práctica común en las herramientas de investigación reproducibles. Las notas de la versión de NumPy documentan estos cambios.

Para la procedencia, almacene la forma, el dtype y un hash de la entrada junto a los resultados. Herramientas como numpy.testing.assert_allclose con tolerancia explícita hacen que las pruebas de regresión sean significativas en lugar de frágiles.

Integrando NumPy con el resto del stack

NumPy rara vez está solo en el procesamiento de datos. pandas envuelve matrices NumPy con ejes etiquetados y es la herramienta adecuada cuando sus datos tienen columnas heterogéneas o etiquetas de fila significativas; la conversión con .to_numpy() es de copia cero cuando los dtypes coinciden. SciPy se basa en NumPy para álgebra lineal, optimización y procesamiento de señales; generalmente se prefiere scipy.linalg a numpy.linalg para cualquier cosa que vaya más allá de las resoluciones básicas. scikit-learn consume y devuelve matrices NumPy en todo momento. Matplotlib las grafica directamente.

El contrato de interoperabilidad es la interfaz de matriz, formalizada como el estándar API de Python Array, que permite a bibliotecas como CuPy, JAX y PyTorch exponer APIs compatibles con NumPy. Escribir código de análisis sobre este subconjunto lo hace portátil a GPUs con modificaciones mínimas, una ventaja real cuando una simulación excede el tamaño de una estación de trabajo.

Una advertencia: las conversiones implícitas entre estas bibliotecas copian datos. Mover una matriz NumPy a una GPU con cupy.asarray de CuPy transfiere los datos a través de PCIe; mantener los datos residentes en un solo dispositivo y agrupar las transferencias es mucho más rápido que realizar viajes de ida y vuelta por operación.

Fuentes y lecturas adicionales

  • Data processing — Wikipedia: Data processing is the collection and manipulation of digital data to produce meaningful information. Data processing is a form of information processing, which…

Preguntas frecuentes

¿Qué es el procesamiento de datos con NumPy?

El procesamiento de datos con NumPy implica el uso del ndarray de la biblioteca NumPy para cargar, limpiar, transformar y reducir datos numéricos. Cubre la lectura de matrices desde archivos, el manejo de valores faltantes con funciones compatibles con NaN, el remodelado, el broadcasting y la agregación a lo largo de ejes. Dado que la mayoría de las bibliotecas científicas de Python dependen de NumPy, es la capa fundamental de los flujos numéricos.

¿Es NumPy más rápido que pandas para el procesamiento de datos?

NumPy es más rápido para matrices numéricas homogéneas porque opera directamente sobre memoria contigua sin la sobrecarga de índices o el despacho de dtypes. pandas es más rápido de escribir y está mejor adaptado a datos tabulares etiquetados de tipos mixtos. Para cálculos numéricos grandes, convertir un DataFrame de pandas a una matriz NumPy con .to_numpy() y procesarlo allí es una optimización común.

¿Cómo manejo los datos faltantes en NumPy?

Las matrices de punto flotante representan los valores faltantes como np.nan, y NumPy proporciona np.nanmean, np.nanstd, np.nansum y np.isnan para trabajar con ellos. Las matrices de enteros no pueden almacenar NaN, por lo que debe convertirlas a flotantes o usar un valor centinela más una máscara booleana. Las matrices enmascaradas a través de np.ma ofrecen una alternativa más estructurada.

¿Puede NumPy procesar datos más grandes que la RAM?

Sí, utilizando np.memmap para mapear un archivo de disco al espacio de direcciones, o leyendo conjuntos de datos HDF5 en fragmentos con h5py. Ambos enfoques mantienen limitada la memoria máxima. Para el procesamiento paralelo o distribuido entre máquinas, Dask y Zarr extienden el mismo modelo de matriz más allá de un solo nodo.

¿Cuál es la diferencia entre una vista y una copia en NumPy?

Una vista comparte el búfer de memoria de la matriz original y solo modifica los metadatos de forma o zancada, por lo que es económica pero las mutaciones se propagan. Una copia asigna nueva memoria y es independiente. El slicing y reshape generalmente devuelven vistas; la indexación sofisticada y .copy() devuelven copias. Utilice arr.base para comprobar si una matriz es una vista.

¿Cómo hago que los resultados de NumPy sean reproducibles?

Utilice np.random.default_rng(seed) en lugar del np.random.seed global heredado, fije la versión de NumPy en su entorno y registre el dtype y la forma con sus salidas. Persista las matrices con np.save en lugar de CSV para preservar exactamente el dtype. Para las pruebas, compare con np.testing.assert_allclose y una tolerancia explícita.

Preguntas frecuentes

¿Qué es el procesamiento de datos de NumPy?

El procesamiento de datos NumPy implica el uso del ndarray de la biblioteca NumPy para cargar, limpiar, transformar y reducir datos numéricos. Cubre la lectura de matrices de archivos, el manejo de valores faltantes con funciones compatibles con NaN, la remodelación y transmisión, y la agregación a lo largo de ejes. Dado que la mayoría de las bibliotecas científicas de Python dependen de NumPy, es la capa fundamental de las canalizaciones numéricas.

¿NumPy es más rápido que los pandas para el procesamiento de datos?

NumPy es más rápido para matrices numéricas homogéneas porque opera directamente en memoria contigua sin índice o sobrecarga de envío de tipos. pandas es más rápido de escribir y más adecuado para datos tabulares etiquetados de tipo mixto. Para cálculos numéricos grandes, convertir un DataFrame de pandas en una matriz NumPy con .to_numpy() y procesarlo existe una optimización común.

¿Cómo manejo los datos faltantes en NumPy?

Las matrices de punto flotante representan valores faltantes como np.nan, y NumPy proporciona np.nanmean, np.nanstd, np.nansum y np.isnan para trabajar con ellos. Las matrices de enteros no pueden almacenar NaN, por lo tanto, conviértalas a flotantes o use un valor centinela más una máscara booleana. Los arreglos enmascarados a través de np.ma ofrecen una alternativa más estructurada.

¿Puede NumPy procesar datos más grandes que la RAM?

Sí, usando np.memmap para asignar un archivo de disco al espacio de direcciones o leyendo conjuntos de datos HDF5 en fragmentos con h5py. Ambos enfoques mantienen limitada la memoria máxima. Para procesamiento paralelo o distribuido entre máquinas, Dask y Zarr extienden el mismo modelo de matriz más allá de un solo nodo.

¿Cuál es la diferencia entre una vista y una copia en NumPy?

Una vista comparte el búfer de memoria de la matriz original y solo modifica los metadatos de forma o zancada, por lo que es barata pero las mutaciones se propagan. Una copia asigna nueva memoria y es independiente. Cortar y remodelar normalmente devuelve vistas; indexación elegante y .copy() devolver copias. Utilice arr.base para comprobar si una matriz es una vista.

¿Cómo puedo hacer que los resultados de NumPy sean reproducibles?

Utilice np.random.default_rng(seed) en lugar del np.random.seed global heredado, fije la versión de NumPy en su entorno y registre el tipo y la forma con sus resultados. Persista las matrices con np.save en lugar de CSV para preservar exactamente el tipo d. Para las pruebas, compárelo con np.testing.assert_allclose y una tolerancia explícita.


Cree un portafolio de datos, proyecto por proyecto

Rutas de ciencia de datos basadas en proyectos con una terminal guiada y conjuntos de datos reales