Leia no arquivo grande e faça o dicionário

Eu tenho um arquivo grande que eu preciso ler e fazer um dicionário. Eu gostaria que isso fosse o mais rápido possível. No entanto, meu código em python é muito lento. Aqui está um exemplo mínimo que mostra o problema.

Primeiro, faça alguns dados falsos

paste <(seq 20000000) <(seq 2 20000001)  > largefile.txt

Agora, aqui está uma pequena parte do código python para ler e criar um dicionário.

import sys
from collections import defaultdict
fin = open(sys.argv[1])

dict = defaultdict(list)

for line in fin:
    parts = line.split()
    dict[parts[0]].append(parts[1])

Horários:

time ./read.py largefile.txt
real    0m55.746s

No entanto, não é I / O ligado como:

time cut -f1 largefile.txt > /dev/null    
real    0m1.702s

Se eu comentar odict linha demora9 segundos. Parece que quase todo o tempo é gasto pordict[parts[0]].append(parts[1]).

Existe alguma maneira de acelerar isso? Eu não me importo de usar cython ou mesmo C se isso vai fazer uma grande diferença. Ou os pandas podem ajudar aqui?

Aqui está a saída do perfil em um arquivo de tamanho de 10000000 linhas.

python -m cProfile read.py test.data         20000009 function calls in 42.494 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 bisect.py:1(<module>)
        1    0.000    0.000    0.001    0.001 collections.py:1(<module>)
        1    0.000    0.000    0.000    0.000 collections.py:25(OrderedDict)
        1    0.000    0.000    0.000    0.000 collections.py:386(Counter)
        1    0.000    0.000    0.000    0.000 heapq.py:31(<module>)
        1    0.000    0.000    0.000    0.000 keyword.py:11(<module>)
        1   30.727   30.727   42.494   42.494 read.py:2(<module>)
 10000000    4.855    0.000    4.855    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
 10000000    6.912    0.000    6.912    0.000 {method 'split of 'str' objects}
        1    0.000    0.000    0.000    0.000 {open}

Atualizar. Podemos supor que partes [1] é um inteiro e que partes [0] é uma cadeia de comprimento fixo curto.

Meus dados falsos não são muito bons, pois você só recebe um valor por chave. Aqui está uma versão melhor.

perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt

A única operação que farei é consultar uma chave para retornar a lista de valores associados a ela.

questionAnswers(4)

yourAnswerToTheQuestion