🎯 Por que 100 linhas e não 10 ou 1.000
100 linhas é o sweet spot empírico que engenheiros de dados experientes convergem após anos de prática. Grande o suficiente para capturar anomalias raras. Pequeno o suficiente para ser lido com atenção em menos de 10 minutos.
linhas — Insuficiente
Anomalias com frequência de 1:50 passam invisíveis. Você vê o "normal" e nunca os casos extremos que vão quebrar o pipeline.
linhas — Ideal ✓
Captura anomalias com frequência 1:50 ou maior. Cabe em uma tela. O cérebro humano processa sem sobrecarga em ~8 minutos.
linhas — Overkill
Custo cognitivo alto demais. A atenção cai após as primeiras 200 linhas. Você lê mais mas detecta proporcionalmente menos.
💡 A Matemática por Trás
Se um problema ocorre em 1% dos registros (1 em 100), você tem 63% de chance de detectá-lo em uma amostra aleatória de 100 linhas. Com 10 linhas, essa chance cai para apenas 9.5%. Com 1.000 linhas, sobe para 99.99% — mas você não precisa de mais de 63% de chance para iniciar a investigação.
📋 Como Amostrar Corretamente
A amostragem estratificada em 3 camadas garante cobertura das regiões mais problemáticas do dataset. Um sample(100) puramente aleatório tende a pegar apenas o "centro" da distribuição e miss as bordas onde estão a maioria das anomalias.
Camada 1 — Topo: 30 linhas (df.head(30))
Os primeiros registros costumam ser os mais antigos ou os importados primeiro.
O topo revela: formato de dados antigos antes de migrações, registros de teste ainda na produção, valores de inicialização do sistema (ex: "admin", "test@test.com"), e o comportamento original do sistema antes de mudanças de produto.
Camada 2 — Meio Aleatório: 40 linhas (df.sample(40, random_state=42))
Registros representativos do comportamento normal do sistema.
O meio aleatório revela: o padrão "típico" dos dados que vai ser a maioria no pipeline, formatos que funcionam corretamente, e a distribuição real de valores em condições normais.
Camada 3 — Bordas Estranhas: 30 linhas (df.nlargest + df.nsmallest)
Os valores mais extremos da coluna principal de valor/data.
As bordas revelam: outliers legítimos vs erros de dado, valores impossíveis ($-500, datas em 2099), registros que vão causar divisão por zero ou overflow, e o range real dos dados vs o range declarado no schema.
Código Python — Amostragem Estratificada
import pandas as pd
df = pd.read_csv('dados.csv')
coluna_valor = 'revenue'
# 3 camadas
topo = df.head(30)
meio = df.sample(40, random_state=42)
bordas = pd.concat([
df.nlargest(15, coluna_valor),
df.nsmallest(15, coluna_valor)
])
# Snippet final
snippet = pd.concat([topo, meio, bordas]).drop_duplicates()
snippet.to_csv('snippets/snippet_100.csv', index=False)
print(f"Snippet salvo: {len(snippet)} linhas únicas")
🔍 O que Procurar nas 100 Linhas
Inspecionar sem saber o que procurar é perder tempo. O checklist de 6 categorias abaixo garante que você não vai perder nenhuma categoria clássica de problema antes de iniciar o pipeline.
Checklist de Inspeção
Linhas idênticas ou quase-idênticas (mesmo ID, datas ligeiramente diferentes)
"null", "N/A", "None", "-", " " (espaço) que pandas não detecta automaticamente
"1.500,00" e "1500.00" na mesma coluna numérica
"TBD", "0", "999", "admin@empresa.com" como placeholder
DD/MM/YYYY, YYYY-MM-DD, Unix timestamp, "15 jan 2025" na mesma coluna
JSON, XML, ou listas dentro de células de texto
💥 Casos Reais de Anomalias Encontradas
Esses casos parecem improváveis até você os encontrar pela primeira vez. Conhecer os padrões comuns transforma o diagnóstico de horas em minutos.
Moedas Misturadas na Coluna "Valor"
A coluna "revenue" continha EUR, USD, JPY e INR sem indicação de qual era qual. As linhas com JPY tinham valores 150x maiores que USD — o pipeline calculava uma "receita total" que era matematicamente impossível. Detectado na linha 47 do snippet.
Solução: Criar coluna "currency" separada e coluna "revenue_usd" com conversão explícita.
JSON Embutido em Célula de Texto
A coluna "description" do Stripe continha strings como {"client_id":"cus_123","plan":"enterprise","mrr":4500}. O MRR de cada cliente estava preso dentro de um JSON que o pandas lia como texto opaco. Detectado nas primeiras 30 linhas do topo.
Solução: df['description'].apply(json.loads) para extrair os campos em colunas separadas.
Três Formatos de Data na Mesma Coluna
Coluna "transaction_date": algumas linhas com "2025-01-15" (ISO), outras com "15/01/2025" (BR), outras com "1736899200" (Unix timestamp). pd.to_datetime() sem format explícito inferia errado e invertia dia/mês silenciosamente para datas ambíguas como "01/12/2025".
Solução: Detectar o formato por regex e aplicar conversão específica para cada padrão.
Idades Negativas por Bug de Migração
A coluna "client_age_days" tinha valores de -45 e -112 nas bordas inferiores do snippet. A causa: a data de criação de alguns clientes tinha sido sobrescrita com uma data de migração futura durante uma atualização em batch. Detectado nas 15 menores linhas (nsmallest).
Solução: Filtro de sanidade (age_days >= 0) com auditoria dos registros negativos antes de corrigir.
Separador Decimal Inconsistente
Coluna "amount": 70% das linhas usavam ponto como separador decimal ("1500.50"), 30% usavam vírgula ("1500,50"). pd.read_csv() lia as linhas com vírgula como string. A soma ficava 30% menor que o real. Detectado na camada aleatória do meio.
Solução: Detectar o padrão com regex e usar pd.read_csv(decimal=',') ou normalizar antes de converter.
📈 Quando Escalar para 1.000 ou 10.000 Linhas
100 linhas é o ponto de partida, não o ponto final. Existem três critérios claros para expandir a amostra — e ignorar esses critérios em datasets simples é desperdício de tempo.
Quando expandir a amostra
Alta Cardinalidade (> 1.000 categorias únicas)
Se a coluna "client_name" tem 5.000 valores únicos, uma amostra de 100 cobre apenas 2%. Para detectar duplicatas fuzzy (nomes quase-iguais), você precisa de pelo menos 500-1.000 linhas.
Sazonalidade Forte (diária/semanal/mensal)
Se o negócio tem picos de sexta-feira ou final de mês, 100 linhas aleatórias podem não cobrir esses períodos. Escale para 1.000 e amostre por período para garantir representatividade temporal.
Análise Estatística com Potência Necessária
Para comparar dois grupos (ex: clientes enterprise vs SMB) e detectar diferenças de 10% com 80% de potência, você precisa de N mínimo calculado via power analysis — tipicamente 200-500 por grupo.
Regra de ouro para decidir
Comece com 100 linhas sempre. Se após a inspeção você identificar um problema que requer validação em escala maior (ex: "parece que há datas invertidas apenas em registros pré-2023"), então expanda para 1.000 focando no subconjunto problemático.
Nunca expanda por precaução — expanda por evidência.
🔒 Protegendo PII na Amostra
Antes de enviar qualquer amostra para análise por agentes de IA, você precisa mascarar ou remover PII (Personally Identifiable Information). Uma linha de código protege você legalmente e protege seus clientes.
⚠️ O que é PII
- •Nome completo de pessoas físicas
- •Endereço de email individual
- •CPF, CNPJ, número de documento
- •Número de telefone
- •Endereço físico
- •Dados financeiros associados a um indivíduo
Código Python — Mascaramento de PII
from faker import Faker
import hashlib
fake = Faker('pt_BR')
df_safe = snippet.copy()
# Substituir nomes por nomes falsos (preserva estrutura)
df_safe['customer_name'] = [fake.name() for _ in range(len(df_safe))]
# Hash de emails (preserva unicidade para análise, remove valor real)
df_safe['email'] = df_safe['email'].apply(
lambda x: hashlib.md5(x.encode()).hexdigest()[:12] + '@masked.com'
if pd.notna(x) else x
)
# Remover colunas de PII direto
df_safe = df_safe.drop(columns=['cpf', 'phone', 'address'])
df_safe.to_csv('snippets/snippet_100_safe.csv', index=False)
print("PII mascarada. Seguro para compartilhar.")
✓ Técnicas de mascaramento
- ✓Faker para nomes e emails sintéticos
- ✓Hash MD5 para análise de unicidade sem valor real
- ✓Tokenização de IDs (ID real → token sequencial)
- ✓Datasets sintéticos para desenvolvimento
✗ Nunca fazer
- ✗Enviar CPF real para análise de IA
- ✗Enviar emails de clientes reais
- ✗Compartilhar dados financeiros identificáveis
- ✗Usar dados de produção em ambientes de teste
✅ Resumo do Módulo
Próximo Módulo:
2.3 — De Disparado para Unificado: pipeline passo a passo do caos ao warehouse limpo