Versionamento de Dados

Visão geral

Versionamento de dados (data versioning) é a prática de atribuir versões estáveis e recuperáveis a conjuntos de dados (datasets) (e, com frequência, aos seus rótulos (labels), características (features) e metadados (metadata)), para que você consiga:

  • Reproduzir as entradas de treinamento (training inputs) exatamente (as mesmas linhas/arquivos, as mesmas saídas de pré-processamento)
  • Rastrear a linhagem (lineage) (de onde os dados vieram, como foram transformados e quais modelos os utilizaram)
  • Auditar e comparar mudanças ao longo do tempo (o que mudou, por que mudou e o que isso afetou)

Em sistemas modernos de aprendizado de máquina (machine learning, ML), apenas o versionamento de código (code versioning) não é suficiente. Se o conjunto de dados que treinou um modelo não puder ser reconstruído, então o modelo é, na prática, não reprodutível, difícil de depurar e complicado de governar.

O versionamento de dados está intimamente relacionado a (e frequentemente é implementado junto de) Pipelines de Dados (ETL/ELT para aprendizado de máquina) (Data Pipelines), Governança de Dados (Data Governance), Documentação de Conjuntos de Dados (Datasheets) (Dataset Documentation), e Qualidade de Dados e Deriva (Data Quality & Drift).

Por que o versionamento de dados importa no aprendizado de máquina

Reprodutibilidade e depuração

Quando o desempenho de um modelo muda, você precisa responder:

  • Os dados mudaram (novos exemplos, exemplos removidos, dados relabelados)?
  • O pré-processamento (preprocessing) mudou (tokenização (tokenization), normalização (normalization), regras de filtragem (filtering rules))?
  • A partição (split) mudou (associação de treino/validação/teste)?
  • Os rótulos mudaram (novas diretrizes, anotadores diferentes, correção de bug)?

Sem versões do conjunto de dados, é fácil chegar em “funcionava semana passada”, mas sem ter como recriar as entradas da semana passada.

Experimentação e avaliação confiáveis

Comparar dois modelos só é significativo se você souber o que diferiu:

  • mesmos dados, código do modelo diferente
  • dados diferentes, mesmo código do modelo
  • mesmo conjunto de treinamento, conjunto de avaliação diferente

O versionamento de dados viabiliza comparações controladas ao fixar (pinning) um instantâneo (snapshot) específico do conjunto de dados (incluindo as partições) para cada experimento.

Conformidade, privacidade e auditabilidade

Muitas organizações precisam ser capazes de provar:

  • de onde os dados vieram (proveniência (provenance))
  • que o uso dos dados foi autorizado
  • que políticas de exclusão/retenção foram aplicadas

O versionamento de dados não substitui práticas de Privacidade (Privacy), mas apoia auditoria e acesso controlado. (Em alguns casos, você precisa projetar o versionamento com cuidado para suportar solicitações de exclusão; veja “Armadilhas” abaixo.)

Conceitos centrais

Identidade do conjunto de dados: o que exatamente é uma “versão do conjunto de dados”?

Uma versão do conjunto de dados deve identificar de forma única:

  1. O conjunto exato de exemplos (linhas, arquivos, documentos, eventos)
  2. O conteúdo exato desses exemplos (bytes / valores)
  3. O esquema (schema) e a semântica (semantics) exatos (significado das colunas, taxonomia de rótulos, unidades)
  4. As partições exatas usadas para treinamento/avaliação (frequentemente ignoradas)

Uma boa regra: se um modelo afirma “treinado na versão X do conjunto de dados”, você deve conseguir reconstruir a entrada de treinamento sem adivinhar.

Imutabilidade vs mutabilidade

Os sistemas mais robustos tratam versões de conjuntos de dados como instantâneos imutáveis:

  • Você pode criar uma nova versão com mudanças
  • Você não deve modificar uma versão existente “no lugar”

A imutabilidade é essencial para auditabilidade e reprodutibilidade. Ela também permite cache consistente e uma linhagem consistente.

Linhagem

Linhagem é o grafo de relacionamentos que mostra:

  • Dados de origem (logs brutos, páginas coletadas por scraping, exportações de fornecedores)
  • Transformações (filtros, junções, limpeza, computação de características)
  • Conjuntos de dados derivados (tabelas de treinamento, conjuntos de características)
  • Consumidores a jusante (modelos, painéis, análises)

A linhagem normalmente é representada como um grafo acíclico direcionado (directed acyclic graph, DAG): cada versão do conjunto de dados é produzida por código + versões de conjuntos de dados a montante.

A linhagem se conecta naturalmente aos seus Pipelines de Dados (ETL/ELT para aprendizado de máquina) e deve ser acompanhada de documentação como Documentação de Conjuntos de Dados (Datasheets).

Metadados

Uma versão do conjunto de dados é muito mais útil quando carrega metadados como:

  • timestamp de criação e autor
  • fontes a montante e identificadores de consulta/pipeline
  • esquema e estatísticas (contagem de linhas, valores ausentes, distribuição de rótulos)
  • restrições de licenciamento/uso
  • uso pretendido e limitações conhecidas
  • resultados de validação (testes de dados, verificações de qualidade)

Metadados também apoiam o monitoramento (monitoring) de Qualidade de Dados e Deriva ao facilitar a comparação de distribuições entre versões.

Abordagens para versionamento de dados

Não existe um único padrão universal de “Git para dados”. Na prática, equipes combinam vários métodos dependendo da escala e da infraestrutura.

1) Instantâneos completos (baseado em cópia)

Ideia: cada versão é uma cópia completa do conjunto de dados naquele ponto no tempo.

Prós

  • Modelo mental simples
  • Fácil de recuperar com exatidão
  • Funciona bem para conjuntos de dados pequenos/médios

Contras

  • Caro para grandes volumes de dados
  • Lento para criar e armazenar
  • Incentiva menos versões, reduzindo a granularidade de auditoria

Isso é comum para conjuntos de avaliação de referência (“golden”) ou conjuntos de dados curados em que o tamanho é administrável.

2) Versionamento incremental/delta (baseado em mudanças)

Ideia: armazenar mudanças entre versões (registros adicionados/removidos/atualizados) ou usar formatos de armazenamento que suportam “viagem no tempo (time travel)”.

Exemplos incluem formatos transacionais de tabelas em arquitetura lakehouse (lakehouse) (Delta Lake, Apache Iceberg, Apache Hudi) que rastreiam versões de tabelas.

Prós

  • Eficiente para conjuntos de dados grandes com atualizações incrementais
  • Suporta consultas “na versão N”
  • Muitas vezes integra-se a fluxos de trabalho de data warehouse/lake

Contras

  • Requer suporte de infraestrutura e governança cuidadosa
  • Atualizações e exclusões em nível de linha (row-level) complicam a reprodutibilidade se não forem modeladas de forma limpa

3) Logs de eventos apenas de acréscimo (append-only) + instantâneos derivados

Ideia: manter os dados brutos como um log apenas de acréscimo (por exemplo, eventos) e definir versões do conjunto de dados como visões determinísticas (deterministic) sobre esse log.

Por exemplo: “todos os eventos até o timestamp T, filtrados pela regra R, juntados à versão V da tabela de referência”.

Prós

  • Trilha de auditoria forte
  • Fácil de raciocinar sobre “o que era conhecido no tempo T”
  • Se encaixa em arquiteturas de streaming e analytics

Contras

  • O determinismo depende de lógica de transformação estável e versionamento de dados de referência
  • Reprocessamentos podem ser caros sem armazenamento em cache (caching)

4) Conjuntos de dados endereçados por conteúdo (content-addressed) (baseado em hash)

Ideia: identificar uma versão do conjunto de dados por uma impressão digital (fingerprint) derivada do seu conteúdo (ou de um manifesto (manifest) de somas de verificação (checksums) de arquivos).

Isso é comum em sistemas como fluxos de trabalho no estilo DVC (DVC-style workflows): armazenar dados em armazenamento de objetos; manter pequenos arquivos de metadados no Git.

Prós

  • Fortes garantias de integridade (integrity guarantees) (o ID da versão corresponde ao conteúdo)
  • Funciona bem com conjuntos de dados baseados em arquivos (imagens, áudio, documentos)

Contras

  • Exige tratamento cuidadoso de manifestos grandes
  • Recalcular hashes pode ser caro, a menos que seja incremental

O que deve ser versionado na prática de aprendizado de máquina?

Muitas falhas em aprendizado de máquina acontecem porque apenas “dados brutos” são versionados, mas não os outros ingredientes que definem a entrada de treinamento.

Dados brutos vs dados de treinamento curados

Em geral, você quer versões em múltiplas camadas:

  • Ingestão bruta: dados não modificados conforme recebidos (logs, dumps)
  • Limpos/normalizados: esquema validado, deduplicados, padronizados
  • Dados rotulados: anotações ligadas a diretrizes e taxonomia de rótulos
  • Conjunto de dados pronto para treino: filtrado, balanceado, particionado, aumentado

Versionar cada camada torna a linhagem mais clara e reduz recomputações.

Rótulos e diretrizes de anotação

Rótulos são dados. Se os rótulos mudarem, isso é uma nova versão do conjunto de dados — mesmo que as entradas sejam idênticas.

Um bom versionamento de rótulos inclui:

  • versão do esquema/taxonomia de rótulos (nomes de classes, mapeamento)
  • versão das diretrizes de anotação
  • pool de anotadores ou identificadores de lote do fornecedor
  • regras de adjudicação (adjudication) e métricas de qualidade (concordância (agreement), auditorias)

Isso se conecta de perto com Coleta e Rotulagem de Dados (Data Collection & Labeling).

Partições (treino/validação/teste)

Um antipadrão (anti-pattern) comum é regenerar partições “aleatoriamente” a cada execução. Para reprodutibilidade, trate as partições como um artefato (artifact) versionado:

  • armazene a lista de IDs de exemplos para cada partição
  • ou armazene uma função determinística de particionamento + semente + espaço de IDs estável

Para dados que crescem ao longo do tempo, você pode precisar de partições sensíveis ao tempo (time-aware) para evitar vazamento (leakage).

Conjuntos de características e saídas de pré-processamento

Se você computa características (por exemplo, representações vetoriais (embeddings), agregações), versione:

  • o código de computação de características
  • a(s) versão(ões) do conjunto de dados de entrada
  • a versão do conjunto de dados/tabela de características de saída
  • parâmetros de configuração (tamanhos de janela, vocabulário, normalizadores)

Caso contrário, você pode acabar com “mesma versão de dados brutos” mas comportamento de modelo diferente devido a mudanças no pré-processamento.

Um modelo mental prático: “versões de conjuntos de dados são commits”

Uma analogia útil é o Git:

  • Uma versão do conjunto de dados é como um commit do Git (commit): imutável, identificada de forma única, recuperável.
  • Um ramo (branch) é como uma linha experimental de conjunto de dados (por exemplo, “novas regras de filtragem”).
  • Uma etiqueta (tag) marca lançamentos importantes (“v1.0 conjunto de treinamento”, “2025-Q4 conjunto de avaliação”).
  • Uma diferença (diff) informa o que mudou (registros/arquivos adicionados/removidos/atualizados).

A principal diferença: conjuntos de dados podem ser enormes, então sistemas de versionamento de dados normalmente armazenam metadados no Git e colocam grandes blobs em armazenamento de objetos ou em formatos especializados de tabela.

Exemplo concreto: versionamento baseado em manifesto para conjuntos de dados em arquivos

Suponha que você treine um classificador de imagens a partir de um diretório de imagens mais um CSV de rótulos.

Um artefato de versão robusto pode incluir:

  • um manifesto listando cada caminho de arquivo + soma de verificação (ou hash de conteúdo (content hash))
  • soma de verificação do arquivo de rótulos + versão do esquema
  • soma de verificação do arquivo de atribuição de partições

Exemplo de dataset_version.json:

{
  "name": "product-images",
  "version": "2026-01-05",
  "source": "s3://ml-data/product-images/",
  "files_manifest_sha256": "b1c6...9af",
  "labels_sha256": "65a2...13d",
  "splits_sha256": "0f8d...c2a",
  "label_schema_version": "3.2",
  "created_by": "data-platform",
  "notes": "Removed duplicates; updated 1,204 labels after audit."
}

Uma forma simples de computar um hash estável de manifesto em Python:

import hashlib
from pathlib import Path

def sha256_file(path: Path, chunk_size=1024 * 1024) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            h.update(chunk)
    return h.hexdigest()

def manifest_hash(root: Path) -> str:
    # Sort paths to ensure deterministic ordering
    entries = []
    for p in sorted(root.rglob("*")):
        if p.is_file():
            entries.append(f"{p.relative_to(root)} {sha256_file(p)}")
    h = hashlib.sha256("\n".join(entries).encode("utf-8"))
    return h.hexdigest()

print(manifest_hash(Path("./train_images")))

Isso produz uma impressão digital que muda se qualquer arquivo mudar, for adicionado, removido ou renomeado. Armazene o hash do manifesto (e idealmente o próprio manifesto) como o identificador da versão do conjunto de dados ou como parte dele.

Exemplo concreto: versionamento de tabela com “viagem no tempo”

Em um padrão lakehouse, conjuntos de dados frequentemente são tabelas em um formato transacional que suporta histórico de versões.

Conceitualmente, você pode fazer:

  • “Me dê a tabela de treinamento como ela existia na versão 128”
  • Treinar o modelo nesse instantâneo estável
  • Registrar “tabela=training_data, versão=128” nos metadados do experimento

O ponto-chave é registrar não apenas o nome da tabela, mas o identificador exato da versão (commit/número de versão) para que o conjunto de dados seja reprodutível.

Essa abordagem é especialmente útil quando conjuntos de dados são grandes demais para fluxos de trabalho baseados em manifesto de arquivos e são atualizados incrementalmente.

Integrando o versionamento de dados aos fluxos de trabalho de aprendizado de máquina

Processo de “lançamento” de conjunto de dados

Um padrão operacional prático é tratar conjuntos de dados como lançamentos de software:

  1. Construir a versão candidata do conjunto de dados a partir das fontes
  2. Executar validações (verificações de esquema, verificações de distribuição, verificações de vazamento)
  3. Calcular estatísticas resumidas e documentação
  4. Aprovar e publicar a versão (imutável)
  5. Notificar consumidores (pipelines de treinamento, analistas)

Publicar pode significar:

  • etiquetar uma versão de tabela como “produção”
  • gravar um registro de versão do conjunto de dados em um catálogo de metadados (metadata catalog)
  • produzir uma exportação congelada para armazenamento de objetos

Fixando versões do conjunto de dados no código de treinamento

O treinamento deve consumir uma versão específica do conjunto de dados, não “a mais recente”.

Exemplo de configuração (YAML):

dataset:
  name: user-clicks-training
  table: lakehouse.ml.user_clicks_train
  version: 128
preprocessing:
  tokenizer_version: 5
  min_session_length: 3

Seu pipeline de treinamento deve registrar esses identificadores junto de:

  • versão do código do modelo (commit do Git)
  • hiperparâmetros (hyperparameters) de treinamento
  • detalhes do ambiente (imagem de contêiner (container image), versões de bibliotecas)

Mesmo um versionamento de conjunto de dados perfeito não ajudará se o pré-processamento for não determinístico ou não rastreado.

Linhagem como um artefato de primeira classe

Em sistemas maduros, cada versão do conjunto de dados é produzida por uma execução de pipeline que registra:

  • versões de conjuntos de dados a montante
  • versão do código de transformação
  • parâmetros
  • ambiente de execução
  • resultados de validação

Isso cria rastreabilidade (traceability) de ponta a ponta de fonte → conjunto de dados → modelo, apoiando depuração e governança (governance).

Ferramentas e ecossistema (opções práticas)

O versionamento de dados pode ser implementado com diferentes pilhas, dependendo das suas restrições.

Ferramentas próximas ao Git para conjuntos de dados em arquivos

Padrão comum:

  • armazenar metadados pequenos no Git
  • armazenar dados grandes em armazenamento de objetos (S3/GCS/Azure)
  • usar uma ferramenta para gerenciar ponteiros (pointers), hashing, cache e downloads reprodutíveis

Isso é adequado para:

  • conjuntos de dados de visão computacional (computer vision) e áudio
  • corpora de processamento de linguagem natural (natural language processing, NLP) curados e distribuídos como arquivos
  • fluxos de trabalho de pesquisa com escala moderada

Formatos de tabela para data lakehouse

Para conjuntos de dados estruturados em grande escala:

  • usar um formato transacional de tabela com histórico de versões
  • registrar a versão/commit da tabela para reprodutibilidade
  • integrar com orquestração de pipelines (pipeline orchestration) e catálogos de metadados

Isso é adequado para:

  • tabelas de fluxo de cliques (clickstream)/sessões
  • dados de treinamento montados por SQL
  • atualizações incrementais e instantâneos “as-of”

Versionamento de armazenamento de objetos (no nível do bucket)

Algumas equipes habilitam versionamento diretamente no armazenamento de objetos e referenciam IDs de versão dos objetos.

Isso pode ajudar, mas raramente é suficiente por si só porque:

  • você ainda precisa de agrupamento em nível de conjunto de dados (quais objetos pertencem à versão X)
  • você ainda precisa de metadados e linhagem
  • renomeações e reorganizações podem ser dolorosas

Armadilhas comuns e como evitá-las

Conjuntos de dados “latest” no treinamento em produção

Se seu pipeline lê de um local mutável (por exemplo, s3://bucket/training/ sobrescrito diariamente), você não consegue reproduzir uma execução anterior.

Correção: publique versões imutáveis (por exemplo, .../training/v2026-01-05/) ou registre IDs de commit de tabela.

Pré-processamento não determinístico

Se o pré-processamento usa aleatoriedade (amostragem, embaralhamento, aumento de dados (augmentation)) sem sementes fixas e configurações registradas, “mesma versão do conjunto de dados” ainda pode resultar em diferentes entradas efetivas.

Correção: trate a configuração de pré-processamento e os controles de aleatoriedade como parte do contrato de “entradas de treinamento”.

Evolução silenciosa de esquema

O significado de uma coluna pode mudar sem que seu nome mude (por exemplo, “price” troca a moeda ou o tratamento de impostos). Isso é uma mudança incompatível semântica (semantic breaking change).

Correção: versione esquemas e documente a semântica; adicione verificações de validação; publique registros de mudanças (changelogs) nos metadados do seu conjunto de dados e na Documentação de Conjuntos de Dados (Datasheets).

Exclusões, solicitações de privacidade e retenção

Se você precisa excluir informações de identificação pessoal (personally identifiable information, PII) ou cumprir o “direito ao esquecimento (right to be forgotten)”, instantâneos imutáveis podem conflitar com a conformidade (compliance) se não forem projetados corretamente.

Abordagens práticas (dependentes de política):

  • manter PII bruta em repositórios controlados e produzir conjuntos de dados derivados preservadores de privacidade (privacy-preserving)
  • projetar instantâneos para que possam ser reconstruídos excluindo indivíduos deletados
  • manter forte controle de acesso (access control) e políticas de retenção (retention) (Segurança de Dados (Data Security), Privacidade)

Vazamento de rótulos entre versões

Se rótulos são atualizados depois do fato (por exemplo, usando informações futuras), você pode acidentalmente vazar conhecimento futuro para instantâneos de treinamento passados.

Correção: versione rótulos com timestamps efetivos; mantenha rotulagem “as-of” para tarefas dependentes do tempo.

Checklist de boas práticas

Mecânica de versionamento

  • Use versões imutáveis do conjunto de dados (instantâneos ou IDs de commit).
  • Versione partições, não apenas registros brutos.
  • Registre impressões digitais de conteúdo (hashes) ou IDs de commit de tabela.

Linhagem e metadados

  • Capture versões de conjuntos de dados a montante + versão do código de transformação.
  • Armazene esquema, estatísticas resumidas e resultados de validação por versão.
  • Mantenha um registro de mudanças: o que mudou e por quê.

Entradas de treinamento reprodutíveis

  • Fixe versões do conjunto de dados nas configurações de treinamento.
  • Rastreie versões de pré-processamento, parâmetros e sementes de aleatoriedade.
  • Garanta que seu pipeline consiga rematerializar a versão do conjunto de dados sob demanda.

Disciplina operacional

Como o versionamento de dados se encaixa na disciplina de “Dados”

Resumo

O versionamento de dados é a base para aprendizado de máquina reprodutível: ele torna mudanças no conjunto de dados explícitas, rastreáveis e recuperáveis. Um versionamento de dados eficaz combina:

  • Identificadores de versão estáveis (instantâneos, commits, hashes)
  • Linhagem (como as versões são produzidas a partir de fontes a montante)
  • Metadados e documentação (esquema, estatísticas, restrições, registros de mudanças)
  • Integração ao fluxo de trabalho (fixar versões no treinamento, lançar conjuntos de dados com validação)

Quando bem feito, o versionamento de dados transforma conjuntos de dados de “alvos móveis” em entradas confiáveis e auditáveis — permitindo depuração mais rápida, experimentos mais significativos e implantações mais seguras.