Selecionando linhas em um arquivo que não contém o valor no outro arquivo

3

Eu tenho dois arquivos. Um deles é um CSV de dados com 60490 linhas. Cada linha é um conjunto de valores, como nome do cliente, datas de serviço, etc.

Um desses valores no primeiro arquivo é um valor VIN.

Eu tenho um segundo arquivo grande que contém uma lista de 92809 VINs.

Eu preciso encontrar uma maneira de excluir todas as linhas do primeiro arquivo que tenham um VIN listado no segundo arquivo.

Eu tentei o grep abaixo. Isso faz o que eu espero que ele faça, mas também é extremamente lento e é morto pelo sistema operacional depois de gerar cerca de 50 linhas.

$ grep -v -f vinlist data.csv > output.csv

Qual é o caminho mais rápido para conseguir isso? Tudo o que encontrei durante a pesquisa parece exigir que dados totalmente ordenados, com linhas em ambos os arquivos, sejam idênticos ou demorem muito tempo / sejam mortos pelo SO

data.csv

123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1C4NJPBB4DD122174,2014-01-20  
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1GMDV33179D147281,2014-01-20  
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1FUYDCYB7WP879651,2014-01-20  
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1FM5K8D8XFGA82149,2014-01-20  
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,5TDBT48A72S003496,2014-01-20  

vinlist:

JF1VA1E6XH9812361  
1HGCP26369A103521  
3N1CN7AP0CL810631  
5XYZK3AB7BG089758  
1FM5K8D8XFGA82149  
4S3BMBG61C3019520  
1FTNE24LX4HA22330  
1N4AL3AP8FC420210  
2GTEC19C491123429  
3N1CN7AP5FL944233  
    
por Arcana 18.06.2017 / 20:35

4 respostas

4

Como sabemos onde o vin está na linha, não precisamos fazer uma pesquisa genérica. Em vez disso, podemos ler as imagens em uma estrutura de dados indexada para permitir consultas rápidas.

Usando o Python, você pode fazer:

Código:

# read the vins into a set to allow fast lookup
with open('file3', 'rU') as f:
    vins = {vin.strip() for vin in f.readlines()}

# go through the data file one line at a time
with open('file2', 'rU') as f:
    for line in f.readlines():

        # get the vin in the line
        vin = line.split(',')[8]

        # if the vin is not in our set, print out the line
        if vin not in vins:
            print(line.strip())

Resultados:

123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1C4NJPBB4DD122174,2014-01-20
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1GMDV33179D147281,2014-01-20
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,1FUYDCYB7WP879651,2014-01-20
123,[email protected],JOE,BLOGGS,123456789,12345-123,"Place Name",12345,5TDBT48A72S003496,2014-01-20
    
por 18.06.2017 / 21:12
2

Usando awk :

Código:

awk -F, 'FNR==NR{a[$1]=1;next} !a[$9] {print}' vin_file data_file

E, como sugerido nos comentários, uma maneira mais eficiente de memória:

awk -F, 'FNR==NR{a[$1];next} (!($9 in a))' vin_file data_file

Como:

  1. Defina o separador de campo como ,
  2. Quando FNR=NR o primeiro arquivo está sendo processado. Neste caso, leia o número vin em um associativo com um valor de 1. Então next para pular o resto do código

  3. Para todos os arquivos após o primeiro, se o número de registro 9 (o vin) não estiver no array associativo, imprima a linha.

por 18.06.2017 / 21:32
2

Você pode usar o comando unix cut para selecionar o vin no arquivo data.csv. Em seguida, use sort e uniq -d para encontrar as vins comuns em ambos os arquivos.

No bash:

cut -d',' -f9 > vin_data
sort vin_data vinlist | uniq -d > vin_to_delete

Você pode então usar python ou sua linguagem de script fav para criar um novo arquivo. Meu script python.

f=open('data_vin_removed.csv','w')
v=[i.strip() for i in open('vin_to_delete')]
for i in open('data.csv'):
    if any([j in i for j in v]):
        continue
    else:
        f.write(i)
f.close() 

Isso criará um arquivo com linhas data.csv que não possuem as vins no vinlist.

    
por 18.06.2017 / 21:21
1

grep é suficiente para esta tarefa:

grep -vFf vinlist data.csv

No entanto, no seu texto de exemplo, há espaços à direita na vinlist, para apará-los: (assumindo o bash, ou outro shell com a sintaxe de substituição do processo)

grep -vFf <(sed -r 's/^[[:blank:]]+|[[:blank:]]+$//g' vinlist) data.csv
    
por 19.06.2017 / 20:54