Obtendo uma seção cruzada de dois arquivos CSV

1

Eu tenho dois arquivos CSV com os quais estou trabalhando. Um é maciço, com cerca de 200.000 linhas. O outro é muito menor, com cerca de 12.000 linhas. Ambos se encaixam no mesmo formato de nomes e endereços de e-mail (tudo é legal aqui, não se preocupe). Basicamente, estou tentando obter apenas um subconjunto da segunda lista, removendo todos os valores que existem atualmente no arquivo maior.

Portanto, a Lista A tem ~ 200k linhas e a Lista B tem ~ 12k. Estas listas se sobrepõem um pouco, e eu gostaria de remover todas as entradas da Lista B se elas também existem na Lista A, deixando-me com valores novos e únicos somente na Lista B. Eu tenho alguns takes à minha disposição que eu pode usar. O Open Office é carregado nesta máquina, junto com o MySQL (as consultas estão bem).

Qual é a maneira mais fácil de criar um terceiro CSV com a interseção de dados?

    
por Sampson 17.05.2010 / 20:24

2 respostas

4

De uma linha de comando do Linux / Unix / Mac:

sort file1 file2 | uniq -d | sort file2 - | uniq -u

Explicação:

Isso retorna apenas as linhas no arquivo2 que não correspondem exatamente a nenhuma linha no arquivo1.

Etapas:

  1. sort file1 file2 : Concatena file1 e file2 juntos, classifica-os e imprime-os para stdout. Observe que as duplicatas serão listadas em linhas adjacentes (duas vezes seguidas) após a classificação.
  2. uniq -d : obtém a saída do comando anterior e imprime somente as linhas duplicadas .
  3. sort file2 - : Concatena o arquivo original2 e a saída do comando anterior (stdout, representado pelo nome do arquivo " - " hífen) e imprime o resultado para stdout. Além disso, todos os itens no arquivo2 que também estavam no arquivo1 serão duplicados (listados duas vezes seguidas) na saída.
  4. uniq -u : obtém a saída do comando anterior e imprime somente itens que não são duplicados (em outras palavras, imprime apenas itens que não estão listados duas vezes seguidas).

Possíveis dicas:

Isto assume que qualquer linha dada no arquivo1 corresponde exatamente uma linha correspondente no arquivo2. Se, por exemplo, arquivo1 e arquivo2 tivessem o mesmo e-mail, mas com capitalização diferente; ou se o arquivo1 tivesse um nome como "Jon Sampson" enquanto o arquivo2 tivesse o mesmo endereço de e-mail com o nome "Jonathan Sampson", eles não seriam considerados duplicados.

Você poderia controlar isso pré-processando o arquivo para remover tudo, exceto o endereço de e-mail e, além disso, minúscula o endereço de e-mail. Os comandos do Unix cut e tr poderiam ser úteis neste caso. Ou você pode alternar para o SQL para cenários mais complexos.

Tamanho do arquivo:

Um arquivo de 200.000 linhas e uma de 12.000 linhas não é tão grande assim. Gerei arquivos de tamanho similar usando o arquivo /usr/share/dict/words no meu MacBook Pro e testei o comando acima; demorou menos de 5 segundos para ser executado.

    
por 17.05.2010 / 22:05
2

Nate deu-lhe uma resposta realmente boa, mas há um caminho mais longo de uma linha de comando Linux / Unix / Mac:

join -t# -v2 <(sort file1.csv) <(sort file2.csv) > result.csv

Advertências:

  • A pergunta original é sobre unir linhas inteiras. A única maneira que posso pensar em
    suprimir a necessidade de join de dividir, é definir o delimitador de campo como um caractere que não é usado em nenhum dos arquivos ( # no meu exemplo). Feio, eu sei.

  • Os arquivos de entrada devem ser classificados no campo de junção. Você pode fazer isso em uma linha (veja acima) mas só funcionará em bash . Outras shells possuem uma sintaxe diferente para isso.

Se seus arquivos de entrada estiverem classificados:

join -t# -v2 file1.csv file2.csv > result.csv

Para o Windows, há uma porta nativa da associação .

    
por 17.05.2010 / 22:21