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.