Verificando acesso...

Início / Trilha 2 — Dicas e Procedimentos Técnicos / Módulo 2.3
MÓDULO 2.3

🔀 De Disparado para Unificado — Pipeline Passo a Passo

5 fontes bagunçadas, formatos incompatíveis, datas inconsistentes — e um warehouse limpo ao final. O procedimento completo em 5 passos que você aplica imediatamente.

6
Tópicos
40
Minutos
Inter.
Nível
Pipeline
Tipo
Pipeline de Unificação
1

🗂️ O Estado Inicial — 5 Fontes sem Padrão Comum

Todo projeto começa aqui: dados caóticos de múltiplas origens. A tentação é ir direto para o código. O engenheiro experiente gasta 30 minutos entendendo o estado inicial antes de escrever uma linha — e economiza horas de retrabalho.

Inventário Inicial — O que mapear

Encoding: UTF-8, Latin-1 (ISO-8859-1), Windows-1252 — acentos quebrados indicam encoding errado
Separador: vírgula, ponto-e-vírgula, tab, pipe — detectar antes de pd.read_csv()
Formato de data: ISO 8601, DD/MM/YYYY, Unix timestamp, texto natural
Header: existe? Está na linha 1? Tem metadados nas primeiras linhas?
Chaves candidatas: qual coluna pode ser usada para juntar com outras fontes
Granularidade: 1 linha = 1 transação? 1 cliente? 1 dia?

💡 Regra de Ouro

Nunca tente juntar fontes antes de entender cada uma individualmente. O JOIN parece funcionar mas os dados estão silenciosamente errados — e você só descobre quando o cliente faz uma pergunta que não fecha com o relatório do mês passado.

2

1️⃣ Passo 1 — Auditar Cada Fonte Individualmente

Aplicar os 4 eixos de auditoria em cada fonte separadamente antes de qualquer tentativa de junção. Cada fonte recebe seu próprio relatório — com problemas identificados e anotação do que precisará de transformação.

Resultado Esperado — Tabela de Diagnóstico

Fonte Linhas Problemas Chave Candidata
Stripe 18.000 JSON embutido em description customer_email
HubSpot 12.000 47% nulos em "source" email
Time Tracker ~8.000 3 formatos de data incompatíveis consultor_nome (normalizado)
QuickBooks ~2.400 Schema muda a cada mês período (year_month)
Founder Tracker ~500 Datas misturadas (3 formatos) client_id
3

2️⃣ Passo 2 — Normalizar Tipos, Datas e Moedas

A etapa de transformação mais trabalhosa: converter tudo para um padrão único. Datas para ISO 8601, moedas para uma base comum, tipos para os corretos. Cada decisão de normalização precisa ser documentada explicitamente.

Normalização de Moedas — 3 Opções

Opção A — Taxa Fixa Atual

Use a taxa de câmbio do dia de hoje para converter todos os históricos.

Prós: simples, zero dependência externa. Contras: impreciso para análises históricas — $1.000 de 2020 não vale o mesmo que $1.000 de 2024.

Opção B — Taxa da Data da Transação via API

Buscar a taxa histórica exata para cada transação via API (ex: Open Exchange Rates, ECB).

Prós: máxima precisão histórica. Contras: dependência de API externa, latência, custo, possível indisponibilidade.

Opção C — Taxa Semanal Fornecida pelo Cliente ✓ Recomendada

O cliente fornece uma tabela de taxas semanais ou mensais. Você aplica a taxa do período correspondente.

Prós: alinhado com como o cliente controla internamente, sem dependência de API, razoavelmente preciso. Esta é a opção padrão para projetos de consultoria.

Normalização de Datas — Código Python

import re
from datetime import datetime

def normalizar_data(valor):
    if pd.isna(valor):
        return pd.NaT
    s = str(valor).strip()
    # Unix timestamp
    if re.match(r'^\d{10}$', s):
        return pd.to_datetime(int(s), unit='s')
    # DD/MM/YYYY
    if re.match(r'^\d{2}/\d{2}/\d{4}$', s):
        return pd.to_datetime(s, format='%d/%m/%Y')
    # YYYY-MM-DD ou datetime
    return pd.to_datetime(s, errors='coerce')

df['date_normalized'] = df['data_original'].apply(normalizar_data)
# Sempre salvar a coluna original
# df['date_original'] permanece intacta
4

3️⃣ Passo 3 — Criar IDs de Junção entre Tabelas

Sem chave de junção confiável, qualquer análise cross-source é invenção. A maioria dos projetos reais não tem IDs universais — você precisa criar a chave a partir dos dados disponíveis.

✓ Estratégias de chave

  • Email normalizado — lowercase + strip() funciona para ~90% dos projetos B2B
  • Hash de campos compostos — MD5(nome + empresa + domínio) para deduplicação
  • ID fornecido pelo cliente — se existe, sempre preferir sobre derivados
  • Surrogate key sequencial — ID novo gerado na fase de processamento

✗ Armadilhas de junção

  • JOIN por nome — "Acme Corp." ≠ "ACME Corp" ≠ "Acme" — fuzzy match obrigatório
  • Fanout não-detectado — JOIN 1:N sem GROUP BY gera linhas duplicadas
  • JOIN sem validar integridade — sempre checar linhas sem match antes de prosseguir

Validação de Integridade Referencial

# Antes do JOIN, sempre verificar:
# Quantos registros do Stripe NÃO têm match no HubSpot?
sem_match = stripe_df[
    ~stripe_df['email_norm'].isin(hubspot_df['email_norm'])
]
print(f"Registros sem match: {len(sem_match)} ({len(sem_match)/len(stripe_df)*100:.1f}%)")

# Se > 10%: investigar antes de continuar
# Se < 2%: documentar e prosseguir com LEFT JOIN
5

4️⃣ Passo 4 — Eliminar Colunas Mortas

Colunas mortas são artefatos de migrações passadas — existem no dataset mas nunca são usadas, frequentemente com 95%+ de nulos ou valor único constante. Eliminá-las é obrigatório antes de entregar um warehouse limpo.

Critérios para Eliminar

  • Nulos > 95%: df.isnull().mean() > 0.95 — coluna essencialmente vazia
  • Variância zero: df['col'].nunique() == 1 — valor único constante (ex: "BR" em todas as linhas)
  • Nomenclatura de migração: colunas "_old", "_backup", "_v1", "_legacy", "_deprecated"
  • Duplicatas de colunas: "customer_id" e "client_id" com os mesmos valores — manter apenas um

Código — Detecção Automática de Colunas Mortas

def detectar_colunas_mortas(df, threshold_nulos=0.95):
    candidatas = []
    for col in df.columns:
        null_rate = df[col].isnull().mean()
        unique_count = df[col].nunique()
        is_legacy = any(s in col.lower() for s in
                       ['_old', '_backup', '_v1', '_legacy', '_deprecated'])

        if null_rate > threshold_nulos:
            candidatas.append((col, f"Nulos: {null_rate:.1%}"))
        elif unique_count <= 1:
            candidatas.append((col, "Variância zero"))
        elif is_legacy:
            candidatas.append((col, "Nomenclatura de migração"))

    return candidatas

# SEMPRE documentar antes de eliminar
colunas_mortas = detectar_colunas_mortas(df_processado)
print("Candidatas à eliminação:", colunas_mortas)
# Revisar manualmente, depois eliminar
df_limpo = df_processado.drop(columns=[c[0] for c in colunas_mortas])

⚠️ Atenção: Sempre documente o que foi removido e por quê antes de deletar. Uma coluna com 96% de nulos pode ser crítica para os 4% de registros onde ela existe — verifique com o cliente antes de eliminar colunas que parecem "visivelmente vazias".

6

5️⃣ Passo 5 — Entregar o Warehouse Limpo e Documentado

O warehouse sem documentação é inútil em 6 meses. A documentação é parte do entregável, não um bônus. Sem ela, o próximo engenheiro (ou você mesmo) vai ter que refazer toda a auditoria.

1

Data Dictionary

Para cada coluna: nome, tipo, descrição em linguagem natural, exemplo de valor, campo obrigatório (sim/não), e SLA de completude. Formato: CSV ou Markdown.

2

README do Pipeline

Instruções para reprocessar o pipeline do zero: quais arquivos de entrada, em que ordem rodar os scripts, quais variáveis de ambiente configurar, e o que verificar para confirmar que a carga foi bem-sucedida.

3

Registro de Decisões (ADR)

Cada decisão não-óbvia documentada: "Usamos taxa de câmbio semanal fornecida pelo cliente porque X"; "Eliminamos a coluna Y porque 97% de nulos — validado com o cliente em 14/05/2026". Salvar em decisions.md.

4

Testes de Validação

Scripts que verificam automaticamente o warehouse entregue: contagem de linhas esperada, ausência de nulos em campos obrigatórios, range de datas correto, totais financeiros batem com os relatórios-fonte.

Resumo do Módulo

Estado inicial mapeado — inventário de fontes antes de qualquer código
Auditoria individual de cada fonte — 4 eixos aplicados antes do JOIN
Normalização com decisões explícitas — taxa de câmbio, formato de data, separador decimal
Chaves de junção criadas e validadas — integridade referencial checada antes do merge
Colunas mortas identificadas e removidas — com documentação do que foi eliminado e por quê
Warehouse entregue com documentação completa — data dictionary + README + decisões + testes

Próximo Módulo:

2.4 — Tabelas-Resumo + DuckDB: transformar dados brutos em tabelas que agentes consultam sem gastar tokens