web-dev-qa-db-fra.com

Utilisation de numpy.genfromtxt pour lire un fichier csv avec des chaînes contenant des virgules

J'essaie de lire dans un fichier csv avec numpy.genfromtxt mais certains champs sont des chaînes contenant des virgules. Les chaînes sont entre guillemets, mais numpy ne reconnaît pas les guillemets comme définissant une seule chaîne. Par exemple, avec les données dans 't.csv':

2012, "Louisville KY", 3.5
2011, "Lexington, KY", 4.0

le code

np.genfromtxt('t.csv', delimiter=',')

produit l'erreur:

ValueError: Certaines erreurs ont été détectées! Ligne # 2 (a 4 colonnes au lieu de 3)

La structure de données que je recherche est:

array([['2012', 'Louisville KY', '3.5'],
       ['2011', 'Lexington, KY', '4.0']], 
      dtype='|S13')

En regardant la documentation, je ne vois aucune option pour y faire face. Existe-t-il un moyen de le faire avec numpy, ou dois-je simplement lire les données avec le module csv puis les convertir en un tableau numpy?

28
CraigO

Vous pouvez utiliser pandas (la bibliothèque par défaut en devenir pour travailler avec des trames de données (données hétérogènes) en python scientifique) pour cela. C'est read_csv peut gérer cela. De la documentation:

quotechar: chaîne

The character to used to denote the start and end of a quoted item. Quoted items 
can include the delimiter and it will be ignored.

La valeur par défaut est ". Un exemple:

In [1]: import pandas as pd

In [2]: from StringIO import StringIO

In [3]: s="""year, city, value
   ...: 2012, "Louisville KY", 3.5
   ...: 2011, "Lexington, KY", 4.0"""

In [4]: pd.read_csv(StringIO(s), quotechar='"', skipinitialspace=True)
Out[4]:
   year           city  value
0  2012  Louisville KY    3.5
1  2011  Lexington, KY    4.0

L'astuce ici est que vous devez également utiliser skipinitialspace=True pour traiter les espaces après le délimiteur de virgule.

Mis à part un puissant lecteur csv, je peux également fortement conseiller d'utiliser pandas avec les données hétérogènes que vous avez (l'exemple de sortie en numpy que vous donnez sont toutes des chaînes, bien que vous puissiez utiliser des tableaux structurés).

20
joris

Le problème avec la virgule supplémentaire, np.genfromtxt Ne résout pas cela.

Une solution simple consiste à lire le fichier avec csv.reader() du module csv de python dans une liste, puis à le vider dans un tableau numpy si vous le souhaitez.

Si vous voulez vraiment utiliser np.genfromtxt, Notez qu'il peut prendre des itérateurs au lieu de fichiers, par ex. np.genfromtxt(my_iterator, ...). Ainsi, vous pouvez envelopper un csv.reader Dans un itérateur et le donner à np.genfromtxt.

Cela irait quelque chose comme ceci:

import csv
import numpy as np

np.genfromtxt(("\t".join(i) for i in csv.reader(open('myfile.csv'))), delimiter="\t")

Cela remplace essentiellement à la volée uniquement les virgules appropriées avec des tabulations.

12
Bitwise

Si vous utilisez un numpy, vous voudrez probablement travailler avec numpy.ndarray. Cela vous donnera un numpy.ndarray:

import pandas
data = pandas.read_csv('file.csv').as_matrix()

Les pandas géreront correctement le cas "Lexington, KY"

4
Michael Yurin

Faire une meilleure fonction qui combine la puissance du module standard csv et recfromcsv de Numpy. Par exemple, le module csv a un bon contrôle et une bonne personnalisation des dialectes, des guillemets, des caractères d'échappement, etc., que vous pouvez ajouter à l'exemple ci-dessous.

L'exemple genfromcsv_mod la fonction ci-dessous lit un fichier CSV compliqué similaire à ce que Microsoft Excel voit, qui peut contenir des virgules dans les champs entre guillemets. En interne, la fonction possède une fonction de générateur qui réécrit chaque ligne avec des délimiteurs de tabulation.

import csv
import numpy as np

def recfromcsv_mod(fname, **kwargs):
    def rewrite_csv_as_tab(fname):
        with open(fname, 'rb') as fp:
            reader = csv.reader(fp)
            for row in reader:
                yield '\t'.join(row)
    return np.recfromcsv(rewrite_csv_as_tab(fname), delimiter='\t', **kwargs)

# Use it to read a CSV file into a record array
x = recfromcsv_mod('t.csv', case_sensitive=True)
2
Mike T