Lies eine große Datei ein und erstelle ein Wörterbuch
Ich habe eine große Datei, die ich einlesen und aus der ich ein Wörterbuch machen muss. Ich möchte, dass das so schnell wie möglich geht. Mein Code in Python ist jedoch zu langsam. Hier ist ein minimales Beispiel, das das Problem zeigt.
Machen Sie zuerst einige gefälschte Daten
paste <(seq 20000000) <(seq 2 20000001) > largefile.txt
Hier ist ein minimaler Python-Code zum Einlesen und Erstellen eines Wörterbuchs.
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])
Timings:
time ./read.py largefile.txt
real 0m55.746s
Es ist jedoch nicht I / O-gebunden als:
time cut -f1 largefile.txt > /dev/null
real 0m1.702s
Wenn ich das auskommentieredict
Linie dauert es9
Sekunden. Es scheint, dass fast die ganze Zeit damit verbracht wirddict[parts[0]].append(parts[1])
.
Gibt es eine Möglichkeit, dies zu beschleunigen? Es macht mir nichts aus, Cython oder sogar C zu verwenden, wenn das einen großen Unterschied machen wird. Oder können Pandas hier helfen?
Hier ist die Profilausgabe in einer Datei mit einer Größe von 10000000 Zeilen.
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}
Aktualisieren. Wir können annehmen, dass parts [1] eine ganze Zahl und parts [0] eine kurze Zeichenfolge mit fester Länge ist.
Meine gefälschten Daten sind nicht sehr gut, da Sie nur einen Wert pro Schlüssel erhalten. Hier ist eine bessere Version.
perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt
Die einzige Operation, die ich ausführen werde, ist das Abfragen eines Schlüssels, um die Liste der damit verbundenen Werte zurückzugeben.