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.

Respuestas a la pregunta(4)

Su respuesta a la pregunta