Redução de Memória e Otimização de Grandes Datasets em Python
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
dtypepara reduzir uso de memória (int32vsint64,float32vsfloat64).
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"])
Carrega somente colunas necessárias, reduzindo footprint.
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
Evite loops Python: use vetorização NumPy ou Pandas.
# Lento
df["nova"] = [x*2 for x in df["inteiros"]]
# Rápido
df["nova"] = df["inteiros"] * 2
Funções vetorizadas reduzem overhead de loops Python.
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
map,filtereitertoolspara 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
Essencial em scripts de ETL com datasets enormes.
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")
downcastconverte para menor tipo possível sem perder precisão.
6.2 Objetos para categorias
Colunas de strings repetidas →
category
df["categoria"] = df["categoria"].astype("category")
7. Paralelização e Computação Distribuída
7.1 Dask
Permite trabalhar com dataframes maiores que memória, paralelizando operações:
import dask.dataframe as dd
df = dd.read_csv("grande_arquivo.csv")
resultado = df.groupby("col1").col2.sum().compute()
Substitui Pandas quando o dataset ultrapassa a RAM.
7.2 Multiprocessing
Para funções puras, use
concurrent.futures.ProcessPoolExecutorpara paralelizar transformações.
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()
Identifica linhas que consomem mais memória, permitindo otimizações pontuais.
8.2 pandas.info(memory_usage="deep")
print(df.info(memory_usage="deep"))
Mostra uso detalhado de memória, incluindo colunas tipo
object.
9. Boas Práticas Profissionais
Use tipos adequados (
int32,float32,category) sempre que possível.Prefira operadores vetorizados a loops Python.
Use chunks, generators e lazy evaluation para datasets gigantes.
Combine Dask ou paralelização para grandes volumes.
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 (
int32,float32,category)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
Postar um comentário