mygems

Como remover linhas duplicadas de um arquivo CSV

A maioria dos duplicados são dois registros de uma pessoa, um mais novo. Veja como encontrá-los e manter o certo.

Por uos ·

Para linhas duplicadas exatas, mantendo o cabeçalho e a ordem original:

awk 'NR==1 || !seen[$0]++' input.csv > deduped.csv

Isso resolve o caso fácil, e o caso fácil é mais raro do que parece. A maioria dos “duplicados” de um arquivo de trabalho não são linhas idênticas, e sim dois registros da mesma pessoa com maiúsculas e minúsculas diferentes, um espaço no final ou um telefone atualizado. Apagar o errado faz você perder dados, então a ordem das operações importa: decida o que torna duas linhas iguais, veja no que elas diferem e só então apague.

Passo um: defina a chave

Um duplicado são duas linhas que descrevem a mesma coisa. Quais colunas estabelecem isso é uma decisão sobre os seus dados, não uma propriedade do arquivo.

  • Um duplicado de linha inteira, com todos os campos idênticos, quase sempre é um erro: uma importação dupla, um job que rodou de novo, uma inclusão que rodou duas vezes. Pode remover sem medo.
  • Um duplicado de chave, mesmo email ou mesmo order_id mas todo o resto diferente, é uma questão de dados. Uma dessas linhas provavelmente é mais recente ou mais completa, e você precisa escolher.

Inverter os dois é a forma clássica de perder registros. Deduplicar por name numa lista de clientes vai apagar sem dó duas pessoas diferentes chamadas James Smith.

Passo dois: conte antes de apagar

Nunca rode uma deduplicação às cegas. Veja o que você está prestes a remover:

duckdb -c "SELECT email, count(*) n FROM read_csv('input.csv') GROUP BY email HAVING n > 1 ORDER BY n DESC LIMIT 20"

Dois números dizem se a sua chave está certa. Se os duplicados são um punhado, provavelmente são digitações duplas de verdade. Se um terço do arquivo está “duplicado”, a chave está errada: você está comparando algo que nunca foi único.

Depois olhe um caso específico por inteiro, que é o passo que todo mundo pula:

duckdb -c "SELECT * FROM read_csv('input.csv') WHERE email = '[email protected]'"

É aí que você descobre que as duas linhas diferem justamente na coluna que importava.

Passo três: escolha qual linha sobrevive

Quando você sabe que as linhas diferem, “remover duplicados” vira “ficar com a certa”. Três regras, mais ou menos na ordem de quantas vezes acertam:

Fique com a mais recente. Se houver um timestamp, normalmente é a resposta.

duckdb -c "COPY (SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY email ORDER BY updated_at DESC) rn FROM read_csv('input.csv')) WHERE rn = 1) TO 'deduped.csv' (HEADER)"

Fique com a mais completa. Sem timestamp, ordenar pelo número de campos não vazios é um bom substituto, porque o registro mais preenchido costuma ser o mais novo. Ordene por (col_a IS NOT NULL)::INT + (col_b IS NOT NULL)::INT + … e pegue a primeira.

Junte as duas. Às vezes cada linha tem algo que falta na outra. É comum e não existe atalho: é um coalesce por coluna, e para um conjunto pequeno vale mais fazer à mão do que automatizar mal para um grande.

Seja qual for a sua escolha, grave as linhas descartadas num segundo arquivo antes de apagá-las. Uma deduplicação que você não consegue desfazer é uma que você vai lamentar em algum momento das próximas duas semanas.

Quase duplicados, que são a maioria

A correspondência exata deixa passar a maior parte dos duplicados reais. Normalize primeiro, compare depois e mantenha os valores originais.

duckdb -c "SELECT lower(trim(email)) k, count(*) n FROM read_csv('input.csv') GROUP BY k HAVING n > 1"

As normalizações a aplicar, mais ou menos em ordem de rendimento:

  • Maiúsculas e minúsculas. [email protected] e [email protected] são a mesma caixa de e-mail.
  • Espaços. Espaços no final, vindos de um copiar e colar, são invisíveis e extremamente comuns. trim() pega os do início e do fim; um replace cuida dos espaços não separáveis que chegam de formulários web.
  • Pontuação em identificadores. Telefones como +44 20 7946 0958, 02079460958 e (020) 7946 0958 são um só número. Remova tudo que não for dígito antes de comparar.
  • Pontos do Gmail e endereços com plus. [email protected] chega na mesma caixa de entrada que [email protected]. Se isso conta como duplicado depende de você estar deduplicando pessoas ou contas.

O que não fazer automaticamente: correspondência aproximada de nomes. “Jon Smith” e “John Smith” podem ser a mesma pessoa ou dois colegas, e um limite de similaridade que serve para um arquivo não serve para o próximo. Gere os pares candidatos, revise e só então aja.

CSV File Viewer - Smart CSViPhone e iPad · Android

O editor SQL e o editor de filtros visuais são as duas metades deste trabalho: um GROUP BY para achar as chaves duplicadas e depois um filtro para ler cada linha que compartilha uma, sem precisar carregar nada antes em um banco de dados.

O que ele faz

Numa planilha

Excel e Sheets têm um comando Remover duplicatas (Remove Duplicates), com uma característica que convém conhecer antes de usá-lo: ele mantém a primeira ocorrência e apaga o resto, sem como dizer qual é a primeira. A ordem em que a planilha estava decide qual registro sobrevive.

Então ordene de propósito antes de executá-lo. Ordene pelo seu timestamp em ordem decrescente, e “manter a primeira” vira “manter a mais nova”, que geralmente é o que você queria.

A outra abordagem em planilha, uma coluna auxiliar com COUNTIF, é mais lenta, mas não destrutiva, e mostra os duplicados em vez de removê-los. Num arquivo grande, também é o que vai travar o Excel, porque COUNTIF em meio milhão de linhas é quadrático.

No celular

A versão realista disso no celular não é uma passada completa de deduplicação. É ordenar pela coluna que você suspeita, rolar a tela e ver as repetições lado a lado, que é o jeito mais rápido de descobrir se um arquivo tem mesmo um problema de duplicados.

Quando você consegue vê-los, filtrar por uma chave e ler as poucas linhas que a compartilham responde à única pergunta que importa: é o mesmo registro ou são dois registros que por acaso compartilham um campo?

CSV Editor - Smart CSViPhone e iPad

Ordene por qualquer coluna como no Excel e depois apague linhas com o filtro aplicado, com segurança: linhas ocultas são protegidas, então uma exclusão nunca toca dados fora do filtro. Desfazer cobre tudo, e é isso que torna razoável fazer esse trabalho no celular.

O que ele faz

Verificando

Três números, e eles devem bater:

wc -l input.csv deduped.csv
duckdb -c "SELECT count(*) rows, count(DISTINCT email) keys FROM read_csv('deduped.csv')"

rows e keys agora devem ser iguais. Se não forem, a deduplicação não foi aplicada a todos os grupos. E input − deduped deve ser igual ao número de linhas que você pretendia remover, o que você contou no passo dois. Se removeu mais que isso, a chave era mais larga ou mais estreita do que você pensava, e o arquivo de linhas descartadas que você guardou é agora o que salva a sua tarde.

Perguntas

Como removo linhas duplicadas de um arquivo CSV?
Para linhas duplicadas exatas, `awk 'NR==1 || !seen[$0]++' input.csv > deduped.csv` mantém o cabeçalho e a ordem original das linhas. Para duplicados definidos por uma coluna-chave e não pela linha inteira, agrupe primeiro por essa chave para ver o que você apagaria, depois escolha qual linha sobrevive, normalmente a mais recente pelo timestamp, em vez de deixar a ferramenta decidir.
Como encontro duplicados num CSV antes de apagá-los?
Conte por chave: `SELECT email, count(*) n FROM read_csv('input.csv') GROUP BY email HAVING n > 1`. Se voltar uma fração grande do arquivo, a chave está errada: você está comparando uma coluna que nunca foi única. Depois selecione todas as linhas de uma chave duplicada e leia-as lado a lado; é aí que você descobre que as linhas diferem numa coluna que importa para você.
Qual linha duplicada devo manter?
A mais recente, se houver um timestamp. Uma janela row_number() particionada pela chave e ordenada por data decrescente mantém exatamente uma linha por chave. Sem timestamp, a linha mais completa é um substituto razoável. Quando cada linha tem algo que falta na outra, a resposta honesta é juntá-las coluna por coluna em vez de descartar qualquer uma.
Por que Remover duplicatas do Excel apaga a linha errada?
Porque ele mantém a primeira ocorrência na ordem atual da planilha e não oferece como influenciar qual é. Ordene pelo seu timestamp em ordem decrescente antes de executá-lo, para que “manter a primeira” signifique “manter a mais nova”.
Como pego duplicados que não são exatamente idênticos?
Normalize para comparar mantendo os valores originais: minúsculas, remoção de espaços e remoção de tudo que não for dígito nos telefones antes de agrupar. Essas três coisas pegam a maioria dos duplicados reais. A correspondência aproximada de nomes é a que você não deve automatizar: “Jon Smith” e “John Smith” podem ser uma pessoa ou duas, e um limite que serve para um arquivo não serve para o próximo.
Como verifico se a deduplicação funcionou?
O número de linhas da saída e o de chaves distintas agora devem ser iguais, e o número de linhas removidas deve bater com o que você contou antes de apagar. Grave antes as linhas descartadas num arquivo separado, porque uma deduplicação que você não consegue desfazer é uma que você vai querer desfazer.

uos — Cria o CSV Editor e o Smart CSV Viewer, e já apagou a linha errada de um par de duplicados vezes suficientes para anotar as verificações.