Leer en archivo grande y hacer diccionario.
Tengo un archivo grande que necesito leer y crear un diccionario. Me gustaría que esto fuera lo más rápido posible. Sin embargo, mi código en python es demasiado lento. Aquí hay un ejemplo mínimo que muestra el problema.
Primero haz algunos datos falsos
paste <(seq 20000000) <(seq 2 20000001) > largefile.txt
Ahora aquí hay una pieza mínima de código python para leerlo y hacer un diccionario.
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])
Tiempos:
time ./read.py largefile.txt
real 0m55.746s
Sin embargo, no está I / O enlazado como:
time cut -f1 largefile.txt > /dev/null
real 0m1.702s
Si comento eldict
línea que toma9
segundos. Parece que casi todo el tiempo lo pasadict[parts[0]].append(parts[1])
.
Hay alguna manera de acelerar esto? No me importa usar cython o incluso C si eso va a hacer una gran diferencia. ¿O pueden los pandas ayudar aquí?
Aquí está la salida del perfil en un archivo de tamaño 10000000 líneas.
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}
Actualizar. Podemos suponer que las partes [1] son un número entero y que las partes [0] es una cadena corta de longitud fija.
Mis datos falsos no son muy buenos ya que solo obtienes un valor por clave. Aquí hay una versión mejor.
perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt
La única operación que haré es consultar una clave para devolver la lista de valores asociados con ella.