Czytaj w dużym pliku i stwórz słownik
Mam duży plik, z którego muszę wczytać i utworzyć słownik. Chciałbym, żeby to było jak najszybciej. Jednak mój kod w Pythonie jest zbyt wolny. Oto minimalny przykład pokazujący problem.
Najpierw wymyśl fałszywe dane
paste <(seq 20000000) <(seq 2 20000001) > largefile.txt
Teraz jest to minimalny fragment kodu Pythona do odczytu i tworzenia słownika.
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])
Czas:
time ./read.py largefile.txt
real 0m55.746s
Jednak nie jest on związany z I / O jako:
time cut -f1 largefile.txt > /dev/null
real 0m1.702s
Jeśli komentujędict
linia bierze9
sekundy. Wydaje się, że prawie cały czas spędzadict[parts[0]].append(parts[1])
.
Czy jest jakiś sposób, żeby to przyspieszyć? Nie mam nic przeciwko używaniu cythona, a nawet C, jeśli to ma duże znaczenie. A może pandy mogą tu pomóc?
Oto dane wyjściowe profilu w pliku o rozmiarze 10000000 linii.
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}
Aktualizacja. Możemy założyć, że części [1] to liczba całkowita, a części [0] to krótki łańcuch o stałej długości.
Moje fałszywe dane nie są zbyt dobre, ponieważ otrzymujesz tylko jedną wartość za klucz. Oto lepsza wersja.
perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt
Jedyną operacją, którą zrobię, jest zapytanie klucza, aby zwrócić listę powiązanych z nim wartości.