26 votes

Comment divisez-vous la lecture d'un grand fichier csv en morceaux de taille égale en Python ?

Dans un premier temps, j'avais le processus suivant.

import csv
reader = csv.reader(open('huge_file.csv', 'rb'))

for line in reader:
    process_line(line)

Voir cette question connexe. Je veux envoyer la ligne de processus toutes les 100 lignes, pour mettre en œuvre le partitionnement par lots.

Le problème lié à la mise en oeuvre de la réponse est que l'objet csv est non indexable et ne peut pas utiliser len.

>>> import csv
>>> reader = csv.reader(open('dataimport/tests/financial_sample.csv', 'rb'))
>>> len(reader)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: un objet de type '_csv.reader' n'a pas de longueur()
>>> reader[10:]
Traceback (most recent call last):
  File "", line 1, in 
TypeError: l'objet 'csv.reader' n'est pas indexable
>>> reader[10]
Traceback (most recent call last):
  File "", line 1, in 
TypeError: l'objet 'csv.reader' n'est pas indexable

Comment puis-je résoudre cela ?

30voto

miku Points 63392

Il suffit de rendre votre lecteur subscriptable en l'entourant d'une list. Évidemment, cela ne fonctionnera pas pour les fichiers vraiment volumineux (voir les alternatives dans les Mises à jour ci-dessous) :

>>> reader = csv.reader(open('big.csv', 'rb'))
>>> lines = list(reader)
>>> print lines[:100]
...

Lecture supplémentaire: Comment diviser une liste en morceaux de taille égale en Python ?


Mise à jour 1 (version list) : Une autre façon possible serait simplement de traiter chaque morceau, au fur et à mesure de leur arrivée lors de l'itération sur les lignes :

#!/usr/bin/env python

import csv
reader = csv.reader(open('4956984.csv', 'rb'))

chunk, chunksize = [], 100

def process_chunk(chuck):
    print len(chuck)
    # faire quelque chose d'utile ...

for i, line in enumerate(reader):
    if (i % chunksize == 0 and i > 0):
        process_chunk(chunk)
        del chunk[:]  # ou : chunk = []
    chunk.append(line)

# traiter le reste
process_chunk(chunk)

Mise à jour 2 (version générateur) : Je ne l'ai pas testé, mais vous pouvez peut-être améliorer les performances en utilisant un générateur de morceaux :

#!/usr/bin/env python

import csv
reader = csv.reader(open('4956984.csv', 'rb'))

def gen_chunks(reader, chunksize=100):
    """ 
    Générateur de morceaux. Prend un `reader` CSV et renvoie
    des tranches de taille `chunksize`. 
    """
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]  # ou : chunk = []
        chunk.append(line)
    yield chunk

for chunk in gen_chunks(reader):
    print chunk # traiter le morceau

# tester gen_chunk sur une séquence factice :
for chunk in gen_chunks(range(10), chunksize=3):
    print chunk # traiter le morceau

# => renvoie
# [0, 1, 2]
# [3, 4, 5]
# [6, 7, 8]
# [9]

Il y a une petite mise en garde, comme l'a souligné @totalhack ici:

Soyez conscient que cela renvoie le même objet à plusieurs reprises avec des contenus différents. Cela fonctionne bien si vous prévoyez de faire tout ce dont vous avez besoin avec le morceau entre chaque itération.

7voto

debaonline4u Points 507

Nous pouvons utiliser le module pandas pour traiter ces gros fichiers CSV.

df = pd.DataFrame()
temp = pd.read_csv('BIG_File.csv', iterator=True, chunksize=1000)
df = pd.concat(temp, ignore_index=True)

2voto

D.Shawley Points 30324

Il n'y a pas de bonne méthode pour le faire pour tous les fichiers .csv. Vous devriez pouvoir diviser le fichier en morceaux en utilisant file.seek pour sauter une section du fichier. Ensuite, vous devez analyser un octet à la fois pour trouver la fin de la ligne. Ensuite, vous pouvez traiter les deux morceaux indépendamment. Quelque chose comme le code suivant (non testé) devrait vous aider à démarrer.

file_one = open('foo.csv')
file_two = open('foo.csv') 
file_two.seek(0, 2)     # aller à la fin du fichier
sz = file_two.tell()    # récupérer le décalage
file_two.seek(sz / 2)   # revenir à la moitié
chr = ''
while chr != '\n':
    chr = file_two.read(1)
# file_two est maintenant positionné au début d'un enregistrement
segment_one = csv.reader(file_one)
segment_two = csv.reader(file_two)

Je ne suis pas sûr comment vous pouvez dire que vous avez fini de parcourir segment_one. Si vous avez une colonne dans le CSV qui est un identifiant de ligne, alors vous pouvez arrêter de traiter segment_one lorsque vous rencontrez l'identifiant de ligne de la première ligne dans segment_two.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X