Como fazer transformação de colunas aninhadas em ETL: passo a passo
Explica-se como extrair e transformar colunas aninhadas (JSON/struct) numa tabela relacional, uma tarefa comum em ETL para preparar dados para análises e relatórios. A transformação de colunas aninhadas simplifica consultas e integrações com ferramentas como Power BI ou SQL.
Pré-requisitos
- Python 3.8+ instalado
- Bibliotecas: pandas e pyarrow (ou json integrado)
- Ficheiro de exemplo em JSON ou CSV com colunas JSON
- Noções básicas de ETL e SQL
Passo 1: Entender o formato aninhado
Analisa um registo de exemplo e identifica as colunas que contêm objetos/arrays JSON. Saber se pretendes normalizar arrays em linhas separadas ou expandir apenas objetos simples determina a estratégia.
# Exemplo de linha JSON num CSV
{
"order_id": 1234,
"customer": {"id": "C001", "name": "Ana"},
"items": [{"sku": "A1", "qty": 2}, {"sku": "B2", "qty": 1}],
"metadata": "{\"source\": \"web\"}"
}
Passo 2: Carregar os dados para um DataFrame
Lê o ficheiro para pandas. Usa dtype adequado para evitar que o pandas trate JSON como strings se já estiverem parseados.
import pandas as pd
# Se for CSV com uma coluna 'payload' em JSON
df = pd.read_csv('orders.csv')
# Ou se for um ficheiro JSON por linha (JSONL)
df = pd.read_json('orders.jsonl', lines=True)
print(df.head())
Passo 3: Expandir objetos JSON simples (colunas aninhadas para colunas)
Quando uma coluna contém um objeto JSON (dict), usa json_normalize ou pandas.json_normalize para expandir campos internos para colunas separadas.
from pandas import json_normalize
# Supondo coluna 'customer' com dicts
customers = json_normalize(df['customer'])
customers.columns = ['customer_' + c for c in customers.columns]
df = pd.concat([df.drop(columns=['customer']), customers], axis=1)
print(df.columns)
Passo 4: Transformar arrays em linhas (explodir arrays)
Para campos que são arrays (ex.: 'items'), converte cada elemento do array numa linha separada usando explode e depois normaliza os elementos.
# Assegurar que 'items' é lista de dicts
df['items'] = df['items'].apply(lambda x: x if isinstance(x, list) else [])
# explode transforma cada item numa linha própria, mantendo order_id
df_exploded = df.explode('items').reset_index(drop=True)
# Normaliza a coluna 'items' agora que contém um dict por linha
items = json_normalize(df_exploded['items'])
items.columns = ['item_' + c for c in items.columns]
# Junta com o resto
df_items = pd.concat([df_exploded.drop(columns=['items']), items], axis=1)
print(df_items.head())
Passo 5: Lidar com campos inconsistentes e tipos
Valida tipos, trata nulls e unifica nomes de colunas. Converte datas e números para tipos apropriados antes da carga final.
# Exemplo: normalizar datas e preencher nulos
df_items['order_date'] = pd.to_datetime(df_items.get('order_date', None), errors='coerce')
df_items['item_qty'] = pd.to_numeric(df_items.get('item_qty', '0'), errors='coerce').fillna(0).astype(int)
# Renomear colunas para convenção SQL-friendly
df_items = df_items.rename(columns=lambda c: c.lower().replace(' ', '_'))
Passo 6: Guardar o resultado para carga (CSV/Parquet/SQL)
Escolhe o formato adequado: CSV/Parquet para ficheiros, ou insere diretamente numa tabela SQL. Parquet preserva tipos e é eficiente para análises.
# Guardar em Parquet
df_items.to_parquet('orders_items.parquet', index=False)
# Ou guardar em CSV para uma carga simples
df_items.to_csv('orders_items.csv', index=False)
Verificar o resultado
Verifica que a contagem de linhas faz sentido: linhas originais multiplicadas pelos elementos do array. Confirma colunas criadas (ex.: customer_id, item_sku) e tipos (datas e inteiros). Testa uma amostra no Power BI ou numa tabela SQL, se possível.
# Exemplos de verificações
print('Linhas originais:', len(df))
print('Linhas após explode:', len(df_items))
print(df_items[['order_id','customer_id','item_sku','item_qty']].head())
Conclusão
Ao transformar colunas aninhadas em tabelas relacionais preparas dados para análises e integração com ferramentas como Power BI ou SQL. Próximos passos: implementar este processo em batch automatizado (Airflow/ETL tool) e adicionar testes/validações. Dica: começa por criar scripts pequenos e validar com amostras antes de processar todo o dataset — que coluna aninhada te causa mais dores de cabeça?