Optimización del rendimiento de Pandas
Pandas es una herramienta de análisis de datos muy potente, pero cuando los conjuntos de datos se vuelven enormes, a menudo se encuentran cuellos de botella de rendimiento.
Para mejorar la eficiencia de Pandas al procesar datos a gran escala, es muy necesario comprender y aplicar algunas técnicas de optimización del rendimiento.
La optimización del rendimiento de Pandas involucra varios aspectos, incluyendo la optimización de tipos de datos, evitar bucles innecesarios, usar operaciones vectorizadas, optimizar índices y cargar grandes conjuntos de datos por bloques, entre otros métodos.
A continuación, presentaremos en detalle varios métodos para optimizar el rendimiento de Pandas.
Usar tipos de datos apropiados
Los tipos de datos en Pandas (dtype) afectan directamente el uso de memoria y la velocidad de cálculo. Elegir los tipos de datos de manera adecuada puede reducir significativamente la ocupación de memoria y acelerar los cálculos.
1. Usar tipos numéricos apropiados
El tipo numérico predeterminado de Pandas esint64yfloat64, pero para la mayoría de los datos, esto puede desperdiciar memoria. Se pueden usar tipos más pequeños, comoint8, int16, float32, etc.
| Método | Descripción |
|---|---|
astype() |
Se utiliza para convertir el tipo de datos de una columna |
downcast |
Reducir el tipo de datos, por ejemplo, convertirint64aint32oint16 |
Ejemplo
# Datos de ejemplo
df = pd.DataFrame({'A': [100, 200, 300, 400], 'B': [1000, 2000, 3000, 4000]})
# Convertir el tipo de datos de la columna a un tipo de datos más pequeño
df['A'] = df['A'].astype('int16')
df['B'] = df['B'].astype('int32')
print(df.dtypes)
Salida:
A int16 B int32 dtype: object
2. Para datos de caracteres, use elcategorytipo
Para columnas de cadenas con valores repetidos, se puede usar elcategorytipo para reducir el consumo de memoria.categoryEl tipo almacena índices enteros en la memoria, en lugar de las cadenas en sí mismas.
Ejemplo
df = pd.DataFrame({'Category': ['A', 'B', 'A', 'C', 'B', 'A']})
# Usar el tipo category
df['Category'] = df['Category'].astype('category')
print(df.dtypes)
Salida:
Category category dtype: object
Usar operaciones vectorizadas en lugar de bucles
Una de las mayores ventajas de Pandas es su capacidad para aprovechar las operaciones vectorizadas y realizar cálculos por lotes de forma rápida. En Pandas, evite en la medida de lo posible los bucles nativos de Python; utilice las funciones integradas de Pandas, de modo que pueda aprovechar la optimización subyacente para realizar cálculos rápidos.
Ejemplo
# Datos de ejemplo
df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]})
# Usar operaciones vectorizadas, evitar usar bucles
df['C'] = df['A'] + df['B']
print(df)
Salida:
A B C 0 1 5 6 1 2 6 8 2 3 7 10 3 4 8 12
En comparación con procesar los datos fila por fila, el uso de operaciones vectorizadas de Pandas puede mejorar significativamente la velocidad de cálculo.
3. Usarapply()yapplymap()para optimizar
Pandas proporciona los métodosapply()yapplymap(), que le permiten aplicar funciones por filas o por columnas en el DataFrame y pueden ser más eficientes que los bucles.
Ejemplo
df['D'] = df['A'].apply(lambda x: x ** 2)
print(df)
Salida:
A B C D 0 1 5 6 1 1 2 6 8 4 2 3 7 10 9 3 4 8 12 16
apply()Es adecuado para procesar datos unidimensionales,applymap()mientras que aplica una función a cada elemento del DataFrame, adecuado para datos bidimensionales.
Ejemplo
df = df.applymap(lambda x: x * 10)
print(df)
Salida:
A B C D 0 10 50 60 10 1 20 60 80 40 2 30 70 100 90 3 40 80 120 160
Usar índices apropiados
Los índices de Pandas pueden mejorar la velocidad de búsqueda de datos, especialmente cuando se necesitan realizar múltiples búsquedas o fusiones de datos; los índices pueden mejorar significativamente la eficiencia. Para grandes conjuntos de datos, asegurarse de usar índices adecuados y reducir operaciones de indexación innecesarias puede mejorar el rendimiento.
Ejemplo
df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]})
df.set_index('A', inplace=True)
# Búsqueda rápida mediante el índice
print(df.loc[2])
Salida:
B 6 Name: 2, dtype: int64
Usar carga por bloques para grandes conjuntos de datos
Cuando el conjunto de datos es demasiado grande, cargar todo el conjunto ocupará mucha memoria e incluso puede causar un desbordamiento de memoria. En este caso, se pueden leer los datos por bloques para reducir la presión sobre la memoria.
Pandas proporciona el parámetrochunksize, que permite cargar los datos por bloques al leer archivos CSV o Excel.
Ejemplo
chunksize = 10000
for chunk in pd.read_csv('large_file.csv', chunksize=chunksize):
# Procesar cada bloque de datos
process(chunk)
Dask y Vaex son dos bibliotecas capaces de manejar conjuntos de datos más grandes que la memoria. Son compatibles con Pandas, admiten computación multihilo y distribuida, y pueden procesar de manera eficiente conjuntos de datos muy grandes.
Ejemplo
# Usar Dask para leer grandes conjuntos de datos
df = dd.read_csv('large_file.csv')
# Realizar operaciones de cálculo
df.groupby('category').sum().compute()
Mediantenumbaacelerar el cálculo
numbaes un compilador JIT que puede acelerar el código Python. Al acelerar el código de procesamiento de datos, se puede mejorar significativamente el rendimiento. Especialmente para operaciones computacionalmente intensivas, como bucles y cálculos numéricos,numbapuede aumentar enormemente la velocidad.
Ejemplo
import pandas as pd
# Función de ejemplo
@numba.jit
def calculate_square(x):
return x ** 2
# Usar numba para acelerar el cálculo
df = pd.DataFrame({'A': [1, 2, 3, 4]})
df['B'] = df['A'].apply(calculate_square)
print(df)
Evitar la asignación encadenada
La asignación encadenada (chained assignment) es una de las trampas de rendimiento comunes en Pandas. Puede causar efectos secundarios innecesarios y, por lo general, ralentiza la velocidad de ejecución. Es mejor usar un método de asignación explícito y evitar realizar múltiples asignaciones en la misma línea.
Ejemplo
df['A'][df['A'] > 2] = 0
# Método de asignación correcto:
df.loc[df['A'] > 2, 'A'] = 0
Optimización de operaciones de combinación
Cuando se necesite combinar varios DataFrames, al usarmerge()oconcat(), debe prestar atención a la optimización de la operación de combinación, especialmente al procesar grandes conjuntos de datos. Se puede usar el parámetroonyhowpara especificar claramente el método de combinación y evitar cálculos innecesarios.
Ejemplo
# Usar el método de combinación adecuado
df1 = pd.DataFrame({'ID': [1, 2, 3], 'Value': ['A', 'B', 'C']})
df2 = pd.DataFrame({'ID': [1, 2, 3], 'Value': ['X', 'Y', 'Z']})
# Usar el parámetro on para realizar la combinación
merged_df = pd.merge(df1, df2, on='ID', how='inner')
print(merged_df)
Salida:
ID Value_x Value_y 0 1 A X 1 2 B Y 2 3 C ZOtras extensiones