Artículos de Tecnología > Data Science

Manipulando datos gigantes con Pandas

alejandro-gamarra
alejandro-gamarra

Hola amigos, ustedes ya se habrán dado cuenta que cuando trabajamos con datos en Python siempre terminamos utilizando la biblioteca Pandas ¿verdad? Y no es por coincidencia, ya que Pandas es una herramienta de análisis y manipulación de datos de código abierto, rápida, potente, flexible y fácil de usar. Siendo una de las piezas clave de la enorme popularidad de Python entre los científicos de datos. Pero los datos de Pandas se manejan en memoria y, por lo tanto, cuando el tamaño de los datos crece es difícil poder trabajar con ellos. Entonces, ¿sólo podremos trabajar con datos pequeños? ¡Claro que no!, la belleza de esta biblioteca es que también está preparada para enfrentar este problema y ustedes, que están leyendo este blog, aprenderán los secretos para superar este desafío.

¡Divide y vencerás!

Quién ya ha escuchado esta frase sabe de lo que estoy hablando, y trabajar con “Big Data” es exactamente esto, así es mis amigos, el secreto es, dividir un banco de datos gigante en particiones más pequeñas y procesar cada una de éstas independientemente para aprovechar todo el potencial de la biblioteca Pandas sin sobrepasar el límite de la memoria al mismo tiempo. Si no dividieramos, simplemente el total de líneas de la base de datos no cabrían en la memoria disponible.

Dividiendo una base

Cuando trabajamos con una tabla o archivo de gran tamaño, de varios gb. El contenido total del archivo no va a caber en la memoria del ordenador. Por eso lo indicado es particionar. Para ello, existe un atributo en la función read_sql ó read_csv de Pandas que permite colocar el número máximo de filas que se cargarán en cada partición. Este atributo es el chunksize. De esta manera, estaríamos importando una partición más pequeña de cada vez en un objeto DataFrame de Pandas, y que podrá ser almacenado en memoria y sobre el cual, nosotros podremos realizar cualquier manipulación en los datos. Veamos 3 ejemplos de cómo realizar esta partición:

1.Importando un archivo CSV gigante

Imaginemos que nos compartieron el archivo CSV “rides.csv” que contiene todos los viajes del mes de una conocida empresa de taxis de una aplicación, y que dentro del archivo CSV existe una columna “estrellas” con la calificación del viaje, el pedido es: “Generar un archivo CSV con únicamente los viajes que tuvieron ‘5’ estrellas”, parece una extracción fácil de realizar ¿verdad?, pero ¿cuál es el problema? El archivo tiene 150MM de líneas, veamos cómo el atributo chunksize nos ayuda con este problema:

# Definimos el tamaño máximo de filas de cada partición (1MM)
import pandas as pd
size = 1000000
# Creamos un objeto iterador 'df_chunk' que contendrá las particiones con 1MM de filas en cada iteración
df_chunk = pd.read_csv('rides.csv', chunksize=size)
# Creamos una variable booleana verdadera 'header' para exportar las cabeceras una única vez
header = True

# Ahora vamos a recorrer cada partición, realizar el filtro solicitado, y exportar el resultado a un nuevo CSV
# El atributo mode='a' (APPEND) sirve para no sobreescribir el archivo Resultado.csv en cada iteración, sino para siempre adjuntar los nuevos resultados
# Luego de la 1ra iteración 'header' vuelve a ser falsa para no colocar nuevamente las cabeceras en el CSV final
for chunk in df_chunk:
    chunk_filter = chunk[chunk['estrellas'] == 5]
    chunk_filter.to_csv('Resultado.csv', header=header, mode='a')
    header = False

2. Importando una tabla SQL gigante

Ahora imaginemos que nos han solicitado exportar a TXT el contenido de una tabla SQL “Factura” que contiene toda la facturación del mes de una conocida empresa de celulares, también parece algo sencillo ¿verdad?, pero nuevamente ¿cuál es el problema? Esta tabla tiene 100MM de líneas, veamos cómo se aplica el atributo chunksize en conexiones sql:

# Importamos las bibliotecas
import pandas as pd
import teradatasql

# Configuramos los datos de conexión al banco SQL
user = "***"
password = "***"
host = '***'
query="SELECT * FROM FACTURA"

# Abrimos la conexión al Banco
with teradatasql.connect(host=host, user=user, password=password, logmech='LDAP') as connect:    
    # Creamos una variable booleana verdadera 'header' para exportar las cabeceras una única vez
    header = True
    # Ejecutamos la query de selección de la tabla 'Factura', pero importamos 1MM de filas de cada vez
    # Para cada 'chunk' (DataFrame con 1MM de filas) exportamos el resultado en un nuevo TXT utilizando el modo 'APPEND'
    for chunk in pd.read_sql(query, connect, chunksize=1000000):
        chunk.to_csv('Factura.txt', header=header, index=None, sep='|', mode='a')
        header = False

3. Importando múltiples archivos

Ahora imaginemos que nuestros datos son tráficos de llamadas de celulares, y nos han compartido 2 años de estos datos, el pedido es: “Subir estos 2 años de tráfico a una tabla y dividirla en archivos mensuales, donde cada archivo tendrá el tráfico de un mes”, pero ¿cuál es el problema? Ya no tenemos un único archivo como fuente de origen, sino que tenemos más de 200 archivos y además la suma de todos ellos generará 250MM de líneas, ahora el problema es mayor, veamos cómo encontrarle una solución:

# Importando bibliotecas
import pandas as pd
import glob

# Configurando el directorio donde se encuentran nuestros archivos
path = r'D:/files'
all_files = glob.glob(path + "/*")

# Ahora vamos a recorrer uno a uno los archivos de nuestro directorio, y dividir cada uno en archivos mensuales
for filename in all_files:
    # Cada archivo será importado al DataFrame 'datos', como no son archivos grandes no usaremos el atributo 'chunksize', aunque ya sabemos como usarlo
    datos = pd.read_csv(filename, sep = '|', header = None, dtype=str)
    # Crearemos nombres de columnas, porque los archivos no los tienen
    datos.columns = ['OPERATOR_ID','MONTH_DT','CUSTOMER_ID','SUBSCRIBER_ID','MSISDN_ID','IMEI_ID','IMSI_ID','TAC_ID','TRAFICO_DT','IMEI_IND','IMEI_ORIGIN_IND','USER_4P_ID','MSISDN_WITH_PREFIX_ID']
    # Actualizaremos el valor de la columna 'MONTH_DT' (YYYYMM) con el año-mes de la fecha del tráfico que se encuentra en la columna 'TRAFICO_DT' (YYYYMMDD)
    datos['MONTH_DT'] = datos['TRAFICO_DT'].str[0:6:1]
    # Ahora crearemos un objeto 'grupos' que tendrá una partición(DataFrame) por cada valor de la columna 'MONTH_DT' 
    grupos = datos.groupby('MONTH_DT')
    # Ahora que ya tenemos dividido nuestro archivo, vamos a guardar cada partición en su respectivo archivo mensual con el modo 'APPEND'
    for mes,valores in grupos:
        if mes=='201901':
            valores.to_csv(r'D:\resultados\TRAFICO_20190100', header=False, index=None, sep='|', mode='a')
        elif mes=='201902':
            valores.to_csv(r'D:\resultados\TRAFICO_20190200', header=False, index=None, sep='|', mode='a')
        # Completar para los demás meses del intervalo de 2 años
        elif mes=='202012':
            valores.to_csv(r'D:\resultados\TRAFICO_20201200', header=False, index=None, sep='|', mode='a')
        elif mes=='202101':
            valores.to_csv(r'D:\resultados\TRAFICO_20210100', header=False, index=None, sep='|', mode='a')
        else:
            valores.to_csv(r'D:\resultados\otros', header=False, index=None, sep='|', mode='a')

Conclusiones

Muy bien amigos, ahora ustedes han comprobado como sí es posible trabajar con datos gigantes (Big Data) aprovechando los recursos de la biblioteca Pandas, sea utilizando el atributo chunksize o sea dividiendo en archivos más pequeños, el objetivo es el mismo, ser capaces de procesar GB de información sin sobrepasar la memoria disponible del ordenador. Por eso, la frase del tema de hoy es: ¡Divide y vencerás! No se olviden de verificar los cursos de Data Science en Alura para aprender más y ¡hasta la próxima!

Puedes leer también:

Artículos de Tecnología > Data Science

En Alura encontrarás variados cursos sobre Data Science. ¡Comienza ahora!

Trimestral

Descuento de lanzamiento de 30%
  • 153 cursos

    Cursos de Programación, Front End, Data Science, Innovación y Gestión.

  • Videos y actividades 100% en Español
  • Certificado de participación
  • Estudia las 24 horas, los 7 días de la semana
  • Foro para resolver tus dudas
  • Acceso completo a la plataforma por 3 meses
US$19,90
un pago de US$29,90 US$19,90
¡QUIERO EMPEZAR A ESTUDIAR!

Paga en moneda local en los siguientes países

Semestral

Descuento de lanzamiento de 30%
  • 153 cursos

    Cursos de Programación, Front End, Data Science, Innovación y Gestión.

  • Videos y actividades 100% en Español
  • Certificado de participación
  • Estudia las 24 horas, los 7 días de la semana
  • Foro para resolver tus dudas
  • Acceso completo a la plataforma por 6 meses
US$33,90
un pago de US$49,90 US$33,90
¡QUIERO EMPEZAR A ESTUDIAR!

Paga en moneda local en los siguientes países

Acceso a todos
los cursos

Estudia las 24 horas,
dónde y cuándo quieras

Nuevos cursos
cada semana