Validação de Dados
Visão geral
Validação de dados (data validation) é a prática de verificar se os dados atendem à estrutura esperada e aos requisitos de qualidade antes de serem usados — especialmente antes do treinamento de modelos (model training) e do serving de modelos (model serving). Em sistemas de IA, a validação normalmente combina:
- Verificações de esquema (schema checks) (tipos, formas, campos obrigatórios)
- Restrições (constraints) (intervalos, categorias permitidas, integridade referencial, regras de negócio)
- Portas de qualidade (quality gates) (regras de aprovação/reprovação baseadas em limites usando estatísticas, detecção de anomalias e verificações de drift)
A validação de dados fica na fronteira entre engenharia de dados e engenharia de aprendizado de máquina. Ela complementa (mas não substitui) a avaliação de modelos (model evaluation) e o monitoramento (monitoring). Quando bem-feita, ela previne falhas silenciosas, reduz o desvio entre treinamento e serving e torna sistemas de ML/LLM mais confiáveis e mais fáceis de depurar.
Este artigo foca em como projetar validação que seja prática em pipelines de produção e robusta à bagunça dos dados do mundo real.
Por que a validação de dados importa em sistemas de ML e LLM
Software tradicional falha de forma explícita: uma função lança uma exceção, um teste falha. ML frequentemente falha silenciosamente: o pipeline roda, um modelo treina, as métricas pioram depois, e a causa raiz fica enterrada nos dados.
Modos comuns de falha que a validação pode detectar cedo:
- Treinar com dados corrompidos ou com tipo incorreto
- Exemplo: uma feature numérica ingerida como string (por exemplo,
"12,345"), ou uma coluna de timestamp interpretada com o fuso horário errado.
- Exemplo: uma feature numérica ingerida como string (por exemplo,
- Bugs em rótulos/target
- Exemplo: rótulos deslocados em um dia por causa de um erro em join; vazamento de target por incluir acidentalmente informação futura.
- Desvio entre treinamento e serving (training-serving skew)
- Exemplo: uma feature calculada com lógica diferente offline vs online; padrões de valor ausente diferem.
- Mudança de distribuição (distribution shift)
- Exemplo: uma nova mudança em um produto upstream faz uma feature categórica introduzir valores não vistos, ou altera o balanceamento de classes.
- Deriva na estrutura de entrada/saída de LLM (LLM input/output structure drift)
- Exemplo: chamadas de ferramentas mudam de forma; uma atualização de template de prompt emite JSON inválido; documentos recuperados incluem HTML ou binário inesperado.
A validação de dados transforma dados “estranhos” em um sinal acionável: falhar o pipeline, colocar o lote em quarentena, bloquear um deploy ou degradar com elegância no serving.
Em termos de MLOps, ela faz parte das suas portas de qualidade junto com testes em CI/CD para Modelos, coordenação de versões em Versionamento (Dados, Código, Modelos) e sinais em tempo de execução em Monitoramento.
O que validar: três camadas de garantias
Um bom modelo mental é validar em três camadas, do mais determinístico ao mais probabilístico.
1) Verificações de esquema (validação sintática)
As verificações de esquema garantem que os dados pareçam com o que o código downstream espera.
Verificações de esquema típicas:
- Colunas/campos obrigatórios existem
- Tipos de dados estão corretos (int/float/string/bool/timestamp)
- Formas e dimensões batem com as expectativas
- Para embeddings: o comprimento do vetor é exatamente 768
- Para imagens: restrições de largura/altura/canais
- Regras de nulabilidade
- Regras básicas de parsing (timestamps fazem parse, JSON faz parse)
Verificações de esquema geralmente são portas rígidas porque o código downstream pode quebrar ou se comportar incorretamente em silêncio se o esquema estiver errado.
2) Restrições (validação semântica)
Restrições garantem que os valores dos dados sejam razoáveis e consistentes com o significado do domínio.
Exemplos:
- Restrições de intervalo:
age ∈ [0, 120] - Não negatividade:
price >= 0,inventory_count >= 0 - Restrições de conjunto permitido:
country_code ∈ ISO-3166 list - Restrições de string: comprimento máximo, padrão regex, identificação de idioma
- Integridade referencial: chaves estrangeiras correspondem a uma tabela de dimensão
- Regras entre campos (lógica de negócio):
end_time > start_timediscount_price <= list_price- Se
is_premium = trueentãosubscription_iddeve estar presente
Restrições podem ser rígidas ou flexíveis dependendo do risco e do ruído esperado. Por exemplo, um único valor fora do intervalo pode ser colocado em quarentena, enquanto uma fração grande pode reprovar o lote.
3) Portas de qualidade (validação estatística e comportamental)
Portas de qualidade usam estatísticas no nível do conjunto de dados e comparações com baselines.
Exemplos:
- Taxas de ausências por feature (por exemplo,
missing_rate(feature_x) < 0.02) - Limiares de balanceamento de classes (por exemplo, taxa positiva dentro de limites históricos)
- Verificações de drift de distribuição (por exemplo, PSI, divergência KL, teste KS)
- Duplicatas e quase-duplicatas
- Taxas de outliers, quantis extremos, mudanças de cardinalidade
- SLAs de pontualidade e frescor dos dados
Essas verificações são inerentemente probabilísticas: distribuições do mundo real mudam. Boas portas consideram sazonalidade e evolução esperada.
Portas de qualidade fazem uma ponte natural para Monitoramento e Avaliação em Produção: a validação captura problemas antes de os dados entrarem no treinamento/serving, enquanto o monitoramento captura problemas que passam despercebidos ou surgem ao longo do tempo.
Validação em treinamento vs serving: objetivos diferentes, táticas diferentes
Validação antes do treinamento
Antes do treinamento, a validação busca garantir:
- O conjunto de dados é internamente consistente e representativo
- Rótulos estão corretos, alinhados e sem vazamento
- O cálculo de features corresponde à lógica de produção
- As fronteiras dos recortes de dados (janelas de tempo, coortes) estão corretas
A validação em tempo de treinamento normalmente roda em pipelines em batch e pode suportar computação mais pesada (varreduras completas, joins caros, profiling).
Verificações comuns em tempo de treinamento:
- Esquema e restrições em conjuntos de dados brutos e processados
- Integridade do split treino/teste
- Sem sobreposição entre identidades de treino e teste (IDs de usuário, IDs de sessão)
- Splits baseados em tempo obedecem à causalidade (sem vazamento do futuro)
- Validação de rótulos
- Conjunto de rótulos permitido
- Taxa de rótulo ausente
- Distribuição de rótulos dentro de limites esperados
- Verificações de vazamento de dados
- Features que se correlacionam “perfeitamente demais” com o target
- Features derivadas de timestamps pós-evento
Validação antes do serving (inferência online ou em batch)
A validação em serving prioriza:
- Segurança e robustez: não derrubar o serviço
- Proteção das suposições do modelo: entradas dentro de intervalos plausíveis
- Controle do raio de impacto: detectar rapidamente quebras upstream
A validação em serving frequentemente precisa ser:
- De baixa latência
- Incremental (por requisição ou pequenos lotes)
- Fail-open ou fail-soft de maneiras cuidadosamente projetadas (por exemplo, features padrão, modelos de fallback)
Verificações em tempo de serving incluem:
- Validação do esquema da requisição (tipos, campos obrigatórios)
- Tratamento de categóricos desconhecidos
- Clipping de intervalos numéricos / verificações de sanidade
- Limites de tamanho de entrada (especialmente para prompts de LLM)
- Verificações de PII e políticas em logs e telemetria (veja Privacidade em Logging)
A validação em tempo de serving também é uma defesa contra desvio entre treinamento e serving, que é uma grande causa de regressões de desempenho em produção em Servir Modelos.
Exemplos práticos
Exemplo 1: Esquema tabular + restrições com Pandera (Python)
Para dados estruturados, uma biblioteca de esquema pode transformar suposições em verificações executáveis.
import pandera as pa
from pandera import Column, Check
import pandas as pd
customer_schema = pa.DataFrameSchema({
"customer_id": Column(str, nullable=False),
"age": Column(int, Check.in_range(0, 120), nullable=False),
"country": Column(str, Check.isin(["US", "CA", "GB", "DE", "FR"]), nullable=False),
"signup_ts": Column(pa.DateTime, nullable=False),
"monthly_spend": Column(float, Check.ge(0.0), nullable=True),
})
df = pd.DataFrame({
"customer_id": ["a1", "a2"],
"age": [34, -5], # invalid
"country": ["US", "ZZ"], # invalid
"signup_ts": ["2025-01-01", "bad"], # invalid
"monthly_spend": [12.5, 0.0],
})
# Raises a detailed exception describing failures
customer_schema.validate(df, lazy=True)
Principais escolhas de design:
- Use restrições rígidas para invariantes (por exemplo, IDs obrigatórios, gasto não negativo).
- Use enumerações para vocabulários controlados, mas com cautela: em produtos globais, listas de países ou versões de app podem evoluir rapidamente. Considere direcionar desconhecidos para
"OTHER"enquanto alerta.
Exemplo 2: Portas de qualidade no nível do conjunto de dados (missingness + drift)
Um padrão comum é comparar estatísticas do lote atual contra um baseline de um período conhecido como bom.
import numpy as np
def missing_rate(x):
return float(np.mean([v is None or (isinstance(v, float) and np.isnan(v)) for v in x]))
def assert_missing_below(name, x, threshold):
rate = missing_rate(x)
if rate > threshold:
raise ValueError(f"{name}: missing rate {rate:.3f} > {threshold:.3f}")
# Example usage
assert_missing_below("monthly_spend", df["monthly_spend"].tolist(), threshold=0.05)
Para drift, você pode calcular o Índice de Estabilidade Populacional (Population Stability Index, PSI) em features numéricas discretizadas (binned). O PSI é popular porque é simples e interpretável, embora dependa das escolhas de bins.
import numpy as np
def psi(expected, actual, bins=10, eps=1e-6):
# expected/actual: 1D arrays
quantiles = np.quantile(expected, np.linspace(0, 1, bins + 1))
quantiles[0], quantiles[-1] = -np.inf, np.inf
def hist(x):
counts, _ = np.histogram(x, bins=quantiles)
p = counts / max(1, counts.sum())
return np.clip(p, eps, 1.0)
e = hist(expected)
a = hist(actual)
return float(np.sum((a - e) * np.log(a / e)))
# Example: if psi_value > 0.2, alert; if > 0.5, fail
psi_value = psi(expected_train_feature, current_batch_feature)
Na prática:
- Trate limites de drift como ajustáveis e específicos por feature.
- Considere sazonalidade esperada (dias úteis/finais de semana, campanhas de marketing).
- Prefira portas flexíveis (alertas) inicialmente para evitar bloquear pipelines por mudança benigna.
Exemplo 3: Validação de requisição em tempo de serving com JSON Schema
Para inferência online, validar payloads de entrada evita que requisições malformadas quebrem seu pipeline de features ou o modelo.
from jsonschema import validate
REQUEST_SCHEMA = {
"type": "object",
"required": ["customer_id", "features"],
"properties": {
"customer_id": {"type": "string", "minLength": 1},
"features": {
"type": "object",
"required": ["age", "country", "monthly_spend"],
"properties": {
"age": {"type": "integer", "minimum": 0, "maximum": 120},
"country": {"type": "string"},
"monthly_spend": {"type": "number", "minimum": 0},
},
"additionalProperties": True
}
},
"additionalProperties": False
}
def validate_request(payload: dict) -> None:
validate(instance=payload, schema=REQUEST_SCHEMA)
Sistemas de serving frequentemente usam um fluxo “validar → normalizar → featurizar”:
- Validar: rejeitar requisições claramente inválidas (tipos errados, campos obrigatórios ausentes).
- Normalizar: aplicar coerções seguras (remover espaços em strings, fazer parse de timestamps).
- Featurizar: calcular features com padrões defensivos.
Isso também sustenta arquiteturas mais robustas como fallbacks e roteadores descritos em Padrões de Design de Sistemas com LLM.
Projetando portas de qualidade: rígidas vs flexíveis, e o que fazer em caso de falha
Uma regra de validação só é tão útil quanto a ação que ela dispara. Uma abordagem comum é definir severidades:
- Bloqueadora (porta rígida): deve passar; caso contrário, pare o pipeline ou rejeite a requisição
- Exemplo: incompatibilidade de esquema, timestamps impossíveis, coluna de rótulo ausente no treinamento
- Degradação (porta flexível): permite o sistema prosseguir, mas com salvaguardas
- Exemplo: missingness levemente elevada; prosseguir com avisos e monitoramento reforçado
- Somente alerta: registrar/notificar; revisar depois
- Exemplo: drift leve de distribuição, pequeno aumento de cardinalidade
Respostas operacionais
Quando uma verificação falha, respostas típicas incluem:
- Falhar rápido em pipelines de treinamento (evita treinar com dados ruins)
- Colocar partições ruins em quarentena (armazenar separadamente, não juntar em tabelas “gold”)
- Comportamento de fallback no serving
- Valores padrão de feature
- Roteamento para um modelo baseline mais seguro
- Retornar uma resposta “cannot score” com códigos de erro claros
- Escalonamento
- Paging para bloqueadores durante janelas críticas
- Notificações via ticket/Slack para problemas de somente alerta
Essas ações se conectam a metas de confiabilidade e orçamentos de erro, em espírito semelhante a SLOs para Features de IA.
Onde a validação de dados se encaixa em uma stack de MLOps
A validação de dados é mais eficaz quando integrada ao longo do ciclo de vida:
- Em pipelines: executar validação como uma etapa de primeira classe antes da materialização de features e do treinamento.
- Em CI: validar conjuntos de dados de amostra e contratos como parte de CI/CD para Modelos.
- Com versionamento: armazenar esquemas, baselines e suites de expectativas junto com versões de dados/modelos em Versionamento (Dados, Código, Modelos).
- Com reprodutibilidade: registrar resultados de validação, estatísticas e exemplos que falham em Treinamento Reprodutível (Configs, Artefatos).
- Com plataformas de features: impor definições de features e estabilidade de tipos em Feature Stores.
- Em produção: conectar sinais de validação a Monitoramento e Avaliação em Produção para detectar degradação cedo.
- Em loops de feedback: usar resultados de validação para melhorar a coleta de dados upstream em Volantes de Dados.
Um conceito particularmente importante é o contrato de dados (data contract): um acordo explícito entre produtores e consumidores de dados sobre esquema, semântica e regras de evolução. Contratos de dados tornam a validação menos ad hoc e reduzem “surpresas de esquema” durante mudanças upstream.
Dados não estruturados e validação específica de LLM
Nem todos os dados de IA são tabulares. A validação deve corresponder à modalidade.
Conjuntos de dados de texto (classificação, recuperação, fine-tuning de LLM)
Verificações úteis:
- Validade de codificação e decodificação (UTF-8)
- Limites de comprimento (mín/máx de tokens ou caracteres)
- Identificação de idioma e filtragem
- Deduplicação / quase-duplicação (importante para vazamento de avaliação)
- Filtros de toxicidade/NSFW dependendo da política
- Presença de campos obrigatórios (instrução, entrada, saída)
Para aplicações com LLM, valide também a estrutura:
- Prompts que precisam produzir JSON devem ser validados com um parser de JSON (e opcionalmente um esquema).
- Argumentos de ferramentas devem ser validados (tipos, intervalos) antes de invocar sistemas externos.
- Documentos recuperados (RAG) devem ser verificados quanto a tamanho, tipo MIME e sanitização.
Essas práticas se conectam naturalmente a PromptOps e Observabilidade para Apps de LLM, onde você acompanha versões de prompt e traces em tempo de execução.
Imagens e áudio
Verificações frequentemente incluem:
- Integridade do arquivo (consegue decodificar?)
- Restrições de forma (largura/altura/canais, taxa de amostragem)
- Frames corrompidos/em branco, segmentos de áudio silenciosos
- Detecção de outliers em estatísticas básicas (intensidade média, faixa dinâmica)
- Consistência de rótulos (bounding boxes dentro dos limites da imagem)
Embeddings e dados vetoriais
Embeddings introduzem modos de falha sutis:
- Incompatibilidade de dimensão (por exemplo, misturar vetores de 768-d e 1536-d)
- Drift na distribuição das normas (mudanças bruscas de escala podem indicar incompatibilidade de modelo/versão)
- NaNs/infs em vetores
- Consistência de indexação (alinhamento entre ID e vetor)
A validação de embeddings é especialmente importante quando você implanta novos modelos de embeddings em paralelo com os antigos.
Catálogo de verificações comuns (prático e de alto valor)
Uma lista concisa de verificações que frequentemente capturam incidentes reais:
Esquema e integridade
- Colunas obrigatórias presentes, nenhuma coluna inesperada (ou permitir explicitamente)
- Verificações de tipo: numérico vs categórico vs timestamp
- Unicidade de chave primária (por exemplo,
row_idúnico) - Integridade referencial para joins (chaves estrangeiras existem)
- Sanidade de particionamento (partições diárias têm a data correta)
Missingness e padrões
- Taxa de ausências por feature abaixo de limites
- Taxa de “valor padrão” abaixo de limites (por exemplo, zeros demais podem indicar quebra no pipeline)
- Padrões de missingness (missing-by-segment) para recortes críticos
Validade de valores
- Verificações de intervalo, regex, enumerações
- Restrições entre campos (horários início/fim, preços)
- Limites de cardinalidade (categorias únicas demais sugerem corrupção)
Consistência estatística
- Média/desvio padrão/quantis dentro de faixas esperadas
- Métricas de drift contra baseline (PSI/KS/KL)
- Taxas de outliers (por exemplo, acima de p99.9)
Rótulos e targets
- Conjunto de rótulos permitido
- Missingness de rótulos
- Mudanças na distribuição de classes
- Verificações de vazamento temporal (timestamps de features precedem a janela do rótulo)
Duplicatas e vazamento
- Duplicatas exatas e quase-duplicatas entre treino/teste
- IDs duplicados com rótulos conflitantes
- Verificações de sobreposição treino/validação/teste
Ferramentas e abordagens de implementação
A ferramenta “certa” depende de onde seus dados vivem e como seus pipelines rodam:
- Validação baseada em dataframe (Python)
- Boa para pipelines de ML, notebooks e código de engenharia de features
- Exemplos: esquemas no estilo Pandera, frameworks baseados em expectativas
- Validação para big data / Spark
- Útil para ETL em larga escala e cálculo de features (verificações de restrição, profiling)
- Validação nativa do warehouse
- Restrições SQL, testes no estilo dbt e verificações agendadas perto da fonte de dados
- Validação no estilo TensorFlow Extended
- Geração de estatísticas + inferência de esquema + detecção de anomalias, frequentemente usada em ecossistemas TF
- Validação na camada de serving
- JSON Schema, modelos no estilo Pydantic ou restrições protobuf em fronteiras de API
Tooling é menos importante do que institucionalizar a validação: torná-la obrigatória, versionada e ligada a decisões de deploy.
Armadilhas e boas práticas
Armadilha: restrições rígidas demais que bloqueiam mudança legítima
Distribuições mudam por razões benignas (lançamentos de produto, novos países). Comece com verificações de drift de somente alerta, aprenda a variabilidade natural e então endureça.
Armadilha: “checks verdes” que não capturam bugs semânticos
Um conjunto de dados pode passar em verificações de esquema e intervalo e ainda estar errado (por exemplo, colunas trocadas, chave de join errada). Adicione verificações entre campos e de integridade de join, e valide “invariantes conhecidas” (como timestamps monotônicos, contagens de ID estáveis).
Armadilha: ignorar o desvio entre treinamento e serving
Valide não só o conjunto de dados de treinamento, mas também a paridade do cálculo de features e as restrições do payload de serving. Feature stores podem ajudar, mas você ainda precisa de verificações em torno de frescor e tratamento de nulos (veja Feature Stores).
Armadilha: registrar dados sensíveis durante a validação
A validação frequentemente inspeciona “linhas ruins”, que podem conter PII. Oculte, faça hash ou amostre com cuidado e siga políticas de Privacidade em Logging.
Boa prática: tratar validação como testes + contratos
- Mantenha esquemas e suites de expectativas em controle de versão.
- Revise mudanças como mudanças de código.
- Anexe artefatos de validação a releases de modelo em um workflow de registry (veja Registro de Modelos).
Boa prática: armazenar baselines e estatísticas
Mantenha estatísticas históricas e uma janela de “baseline dourado”. Isso torna a detecção de drift significativa e ajuda a depurar regressões rapidamente.
Um checklist prático (treinamento e serving)
Antes do treinamento (batch):
- Verificações de esquema/tipo em tabelas brutas + processadas
- Limiares de nulabilidade e missingness
- Restrições de intervalo + valores permitidos
- Verificações de integridade de join/referencial para geração de features
- Correção de rótulos: conjunto permitido, missingness, distribuição
- Integridade do split: sem vazamento entre tempo/IDs
- Verificações de drift vs último conjunto de dados de treinamento bem-sucedido
Antes do serving (inferência online/batch):
- Validação do esquema da requisição (tipos, campos obrigatórios)
- Regras seguras de normalização/coerção
- Verificações de intervalo + política de clipping
- Política para categoria desconhecida (mapear para OTHER, rejeitar ou fallback)
- Limites de tamanho do payload/tokens (especialmente para entradas de LLM)
- Políticas de ocultação de logs e reporte seguro de erros
Resumo
A validação de dados é uma capacidade fundamental de MLOps: ela impõe esquemas, restrições e portas de qualidade que protegem tanto o treinamento quanto o serving contra defeitos nos dados e mudanças upstream. As implementações mais fortes combinam verificações determinísticas (esquema/restrições) com verificações estatísticas (drift, missingness, mudanças de distribuição), estão ligadas a ações concretas (bloquear/quarentenar/fallback) e são integradas a CI/CD, versionamento e monitoramento.
Se você construir apenas uma coisa: implemente baseline automatizado de esquema + missingness + drift como portas automáticas e conecte falhas a respostas operacionais claras. Só isso já previne uma grande fração de incidentes reais de ML no mundo.