2010-06-05 14 views
2

accélérer l'analyse des fichiers

cette fonction est très lent, prend ~ 6 secondes pour un fichier qui est relativement faible (moins de 30.000 lignes.)

comment puis-je accélérer?

def csv2dictlist_raw(filename, delimiter='\t'): 
    f = open(filename) 
    header_line = f.readline().strip() 
    header_fields = header_line.split(delimiter) 
    dictlist = [] 
    # convert data to list of dictionaries 
    for line in f: 
    values = map(tryEval, line.strip().split(delimiter)) 
    dictline = dict(zip(header_fields, values)) 
    dictlist.append(dictline) 
    return (dictlist, header_fields) 

en réponse aux commentaires:

Je sais qu'il ya un module csv et je peux l'utiliser comme ceci:

data = csv.DictReader(my_csvfile, delimiter=delimiter) 

ce qui est beaucoup plus rapide. Cependant, le problème est qu'il ne convertit pas automatiquement les éléments qui sont évidemment des nombres flottants et des entiers en nombres et les transforme en chaînes. Comment puis-je réparer cela? L'utilisation de la classe "Sniffer" ne fonctionne pas pour moi. Quand je l'essayer sur mes fichiers, je reçois l'erreur:

File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/csv.py", line 180, in sniff 
    raise Error, "Could not determine delimiter" 
Error: Could not determine delimiter 

Comment puis-je faire DictReader analyser les champs dans leurs types quand il est évident?

merci.

merci.

+3

Vous savez qu'il y a un module ['csv'] (http://docs.python.org/library/csv.html) non? – kennytm

+2

S'il y a un 'deadbeef' alors * évidemment * c'est une base 16 int, non? Python ne * devine pas *, toi non plus. –

Répondre

3
import ast 

# find field types 
for row in csv.DictReader(my_csvfile, delimiter=delimiter): 
    break 
else: 
    assert 0, "no rows to process" 
cast = {} 
for k, v in row.iteritems(): 
    for f in (int, float, ast.literal_eval): 
     try: 
      f(v) 
      cast[k] = f 
      break 
     except (ValueError, SyntaxError): 
      pass 
    else: # no suitable conversion 
     cast[k] = lambda x: x.decode(encoding) 

# read data 
my_csvfile.seek(0) 

data = [dict((k.decode(encoding), cast[k](v)) for k, v in row.iteritems()) 
     for row in csv.DictReader(my_csvfile, delimiter=delimiter)] 
+0

merci beaucoup. Une autre question à ce sujet: comment puis-je obtenir DictWriter pour sérialiser le lecteur d'un fichier CSV que j'ai lu? Dois-je écrire une méthode personnalisée pour cela? – user248237dfsf

+1

@ user248237: 'writer.writerows (data)' sérialise la liste des dicts. Si vos données contiennent des chaînes non ascii, vous avez besoin d'un script personnalisé similaire à 'UnicodeWriter' sur http://docs.python.org/library/csv.html#examples – jfs

1

Je vois plusieurs problèmes avec votre code:

  • Pourquoi avez-vous besoin dicts? Les clés sont stockées dans chaque instance dict ce qui augmente la consommation de mémoire.

  • Avez-vous vraiment besoin de conserver toutes les instances en mémoire ou serait-ce une option pour utiliser yield?

  • Essayer de convertir chaque valeur prend du temps et n'a aucun sens dans mon option. Si vous avez une colonne ayant les valeurs "abc" et "123" la dernière valeur devrait probablement être une chaîne. Le type d'une colonne doit donc être corrigé et vous devez rendre la conversion explicite.

  • Même si vous souhaitez utiliser votre logique de conversion: Utilisez le module csv et convertissez les valeurs par la suite.

+0

Je suis d'accord qu'il ne devrait pas être tout chargé en mémoire - c'est bien, et csv.DictReader ne fait pas cela. Mais je pense que dictreader devrait certainement reconnaître que quand un champ a toutes les entrées qui ressemblent à 5.34 ou 0.05 alors il devrait être un float, et pas une chaîne, et dans mes fichiers il ne le fait pas (Sniff est capable de détecter le délimiteur/terminateur de ligne, mais pas cela.) Comment puis-je faire en sorte que les types évidents soient déduits? – user248237dfsf

+0

Aussi: Je ne veux pas convertir chaque ligne indépendamment - Je suis d'accord que le type de chaque colonne doit être corrigé, mais je ne peux pas obtenir DictReader pour inférer qu'une colonne a tous les flottants même si toutes les valeurs dans cette colonne sont flotte – user248237dfsf

1

Qu'en est-pandas géants?

import pandas as pd 

# load everything in 
df = pd.read_table(filename) 

# coerce strings to numeric 
df = df.convert_objects(convert_numeric=True)