Читай в большом файле и составь словарь
У меня есть большой файл, который мне нужно прочитать и создать словарь. Я бы хотел, чтобы это было как можно быстрее. Однако мой код на python слишком медленный. Вот минимальный пример, который показывает проблему.
Сначала сделайте поддельные данные
paste <(seq 20000000) <(seq 2 20000001) > largefile.txt
Теперь вот минимальный кусок кода на Python для чтения и создания словаря.
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])
Тайминги:
time ./read.py largefile.txt
real 0m55.746s
Однако это не связано с I / O как:
time cut -f1 largefile.txt > /dev/null
real 0m1.702s
Если я закомментируюdict
линия занимает9
секунд. Кажется, что почти все время тратится наdict[parts[0]].append(parts[1])
.
Есть ли способ ускорить это? Я не против использования Cython или даже C, если это будет иметь большое значение. Или панды могут помочь здесь?
Вот вывод профиля на файл размером 10000000 строк.
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}
Обновить. Можно предположить, что parts [1] - целое число, а parts [0] - короткая строка фиксированной длины.
Мои поддельные данные не очень хороши, так как вы получаете только одно значение за ключ. Вот лучшая версия.
perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt
Единственная операция, которую я сделаю, - это запрос ключа, чтобы вернуть список значений, связанных с ним.