Redução de Memória e Otimização de Grandes Datasets em Python

Trabalhar com datasets grandes em Python pode se tornar lento ou até inviável se não houver estratégias de otimização de memória e processamento. Com técnicas avançadas, é possível reduzir footprint de memória, acelerar operações e manter pipelines escaláveis.


1. Escolha de Tipos de Dados Otimizados

1.1 NumPy Arrays

  • Arrays NumPy são muito mais eficientes que listas Python.

import numpy as np

lista = list(range(10**6))
arr = np.array(lista, dtype=np.int32)  # menor uso de memória
  • Defina explicitamente dtype para reduzir uso de memória (int32 vs int64float32 vs float64).


1.2 Pandas: tipos otimizados

import pandas as pd

df = pd.DataFrame({
    "inteiros": range(10**6),
    "categorias": ["A", "B", "C", "D"]*250000
})

# Reduzindo tipo inteiro
df["inteiros"] = df["inteiros"].astype("int32")

# Convertendo colunas com repetição para category
df["categorias"] = df["categorias"].astype("category")
  • category é ideal para colunas com valores repetidos, reduzindo drasticamente uso de memória.


2. Carregamento Inteligente de Dados

2.1 Leitura seletiva

df = pd.read_csv("grande_arquivo.csv", usecols=["col1","col2"])

2.2 Leitura em chunks

chunksize = 10**5
for chunk in pd.read_csv("grande_arquivo.csv", chunksize=chunksize):
    process(chunk)
  • Processa o dataset em blocos, sem carregar tudo na memória.


3. Operações Vetorizadas e Funcionais

# Lento
df["nova"] = [x*2 for x in df["inteiros"]]

# Rápido
df["nova"] = df["inteiros"] * 2

4. Uso de Generators e Iteradores

  • Para datasets gigantes que não cabem em memória:

def gera_dados(n):
    for i in range(n):
        yield i**2

for valor in gera_dados(10**7):
    process(valor)
  • Não cria listas intermediárias, economizando memória.

  • Combinável com funções mapfilter e itertools para pipelines eficientes.


5. Remoção de Dados Desnecessários

  • Apague variáveis intermediárias após uso:

del df_intermediario
import gc
gc.collect()  # força coleta de lixo

6. Otimização de Tipos Avançada

6.1 Inteiros e floats

df["col_int"] = pd.to_numeric(df["col_int"], downcast="unsigned")
df["col_float"] = pd.to_numeric(df["col_float"], downcast="float")
  • downcast converte para menor tipo possível sem perder precisão.

6.2 Objetos para categorias

df["categoria"] = df["categoria"].astype("category")

7. Paralelização e Computação Distribuída

7.1 Dask

import dask.dataframe as dd

df = dd.read_csv("grande_arquivo.csv")
resultado = df.groupby("col1").col2.sum().compute()

7.2 Multiprocessing


8. Técnicas de Profiling de Memória

8.1 memory_profiler

from memory_profiler import profile

@profile
def processa():
    df = pd.read_csv("grande_arquivo.csv")
    df["nova"] = df["col1"] * 2
    return df

processa()

8.2 pandas.info(memory_usage="deep")

print(df.info(memory_usage="deep"))

9. Boas Práticas Profissionais

  1. Use tipos adequados (int32float32category) sempre que possível.

  2. Prefira operadores vetorizados a loops Python.

  3. Use chunks, generators e lazy evaluation para datasets gigantes.

  4. Faça coleta de lixo e limpeza de variáveis intermediárias.

  5. Combine Dask ou paralelização para grandes volumes.

  6. Documente pipeline e otimizações, permitindo manutenção futura.


10. Conclusão

  • Reduzir memória e otimizar grandes datasets é crucial para performance e escalabilidade.

  • Técnicas avançadas incluem:

    • Uso correto de tipos (int32float32category)

    • Carregamento seletivo e em chunks

    • Vetorização e funções funcionais

    • Generators e pipelines lazy

    • Paralelização e frameworks distribuídos (Dask)

  • Combinadas, essas estratégias permitem processar milhões de registros de forma eficiente, mantendo scripts Python rápidos e escaláveis.

Comentários

Postagens mais visitadas deste blog

Gerando Relatórios em PDF com Python (ReportLab e FPDF)

Manipulação de Arquivos no C#: Como Ler, Escrever e Trabalhar com Arquivos de Forma Simples

Laços de Repetição em Python: Conceitos e Exemplos Práticos