2010-04-19 3 views
9

Ich habe eine CSV-Format-Datei bekommen, die wie folgt aussieht:Lesen von CSV-Dateien in numpy wo Trennzeichen ""

"FieldName1", "FieldName2", "FieldName3", "FieldName4"
"04/13/2010 14: 45: 07.008", "7.59484916392", "10", "6.552373"
"13.04.2010 14: 45: 22.010", "6.55478493312", "9", " 3.5378543"
...

Hinweis, dass es doppelte Anführungszeichen am Anfang und Ende jeder Zeile in t Die CSV-Datei und die Zeichenfolge "," werden zum Abgrenzen von Feldern innerhalb jeder Zeile verwendet. Die Anzahl der Felder in der CSV-Datei kann von Datei zu Datei variieren.

Wenn ich versuche, dies in numpy zu lesen über:
import numpy as np
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True)
alle Daten wird als String-Werte eingelesen, umgeben von doppelten Anführungszeichen. Nicht unvernünftig, aber nicht viel zu mir, als ich dann zurück zu gehen und jede Spalte auf ihren korrekten Typ umwandeln

Wenn ich delimiter='","' stattdessen alles funktioniert wie Ich mag würde, außer für den ersten und letzten Felder. Da der Anfang von Zeilen- und Zeilenendenzeichen ein einzelnes Anführungszeichen ist, wird dies nicht als gültiges Trennzeichen für das erste und das letzte Feld angesehen, so dass sie z. "04/13/2010 14:45:07.008 und 6.552373" - notieren Sie die führenden und abschließenden doppelten Anführungszeichen jeweils. Aufgrund dieser redundanten Zeichen nimmt numpy an, dass die ersten und letzten Felder beide String-Typen sind; Ich will nicht, dass der Fall

Gibt es eine Möglichkeit der anweist numpy sein, Dateien zu lesen, in denen auf diese Weise formatierten, wie Ich mag würde, ohne zu haben, gehen Sie zurück und „reparieren“ die Struktur des numpy Array nach dem ersten Lesen?

Antwort

12

Das grundlegende Problem ist, dass NumPy nicht das Konzept versteht Zitate von Strippen (während das csv Modul der Fall ist). Wenn Sie delimiter='","' sagen, du bist NumPy zu sagen, dass die Spaltenbegrenzer ist buchstäblich ein zitierte Komma, das heißt die Anführungszeichen sind um das Komma, nicht der Wert, also die zusätzlichen Anführungszeichen erhalten Sie auf er ersten und letzten Spalten erwartet.

an den Funktions docs Sehen, ich glaube, Sie werden den converters Parameter festlegen müssen Angebote für Sie Streifen (der Standard nicht):

import re 
import numpy as np 

fieldFilter = re.compile(r'^"?([^"]*)"?$') 
def filterTheField(s): 
    m = fieldFilter.match(s.strip()) 
    if m: 
     return float(m.group(1)) 
    else: 
     return 0.0 # or whatever default 

#... 

# Yes, sorry, you have to know the number of columns, since the NumPy docs 
# don't say you can specify a default converter for all columns. 
convs = dict((col, filterTheField) for col in range(numColumns)) 
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True, 
    converters=convs) 

Oder np.genfromtxt() verlassen und lassen csv.csvreader geben Sie die Datei Inhalte zu einem Zeitpunkt eine Zeile, als Listen von Strings, dann nur Sie durch die Elemente durchlaufen und die Matrix bauen:

reader = csv.csvreader(csvfile) 
result = np.array([[float(col) for col in row] for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

EDIT: okay, so sieht es aus wie Ihre Datei nicht alle Schwimmer ist. In diesem Fall können Sie convs gesetzt, wie im genfromtxt Fall benötigt, oder einen Vektor von Konvertierungsfunktionen im csv.csvreader Fall erstellen:

reader = csv.csvreader(csvfile) 
converters = [datetime, float, int, float] 
result = np.array([[conv(col) for col, conv in zip(row, converters)] 
    for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

EDIT 2: Okay, zählen variable Spalt ... Ihre Datenquelle nur will um das Leben schwer zu machen. Glücklicherweise können wir einfach magic verwenden ...

reader = csv.csvreader(csvfile) 
result = np.array([[magic(col) for col in row] for row in reader]) 

... wo magic() nur einen Namen, die ich für eine Funktion, um die Spitze von meinem Kopf ausstieg. (! Psyche)

Im schlimmsten Fall könnte es sein, so etwas wie:

def magic(s): 
    if '/' in s: 
     return datetime(s) 
    elif '.' in s: 
     return float(s) 
    else: 
     return int(s) 

Vielleicht NumPy eine Funktion hat, die einen String und gibt ein einzelnes Element mit der richtigen Art. numpy.fromstring() schaut nah, aber es könnte den Raum in Ihren Zeitstempeln als Spaltentrennzeichen interpretieren.

P.S. Ein Nachteil mit csvreader Ich sehe ist, dass es Kommentare nicht verwirft; echte csv Dateien haben keine Kommentare.

+1

Die Methode 'str.replace ('' ',' ')' sollte merklich schneller als der reguläre Ausdruck ausgeführt werden, wenn die Eingabedatei groß ist (viele MBs oder GBs) und korrekt ist, wenn Sie annehmen können. 'Charakter erscheint nicht in der Mitte eines Feldes, nur an den Enden. – gotgenes

+0

Danke Mike und Gotgenes, aber ich hätte auch erwähnen sollen, dass die CSV-Datei eine variable Anzahl von Spalten hat. Ich könnte wahrscheinlich den Ansatz, den Sie beschrieben haben, verwenden, indem Sie einen ersten Schritt hinzufügen, um den ersten Datensatz der Datei einzulesen, um die Anzahl der Spalten zu bestimmen, und diese dann als Eingabe für spätere Schritte verwenden, aber es scheint ziemlich klobig zu sein. Gibt es einen besseren Weg? – monch1962

+0

Kleiner Hinweis: Sie müssen 're.compile()' nicht verwenden, da nur die Verwendung von 're.match()' direkt den kompilierten regulären Ausdruck zwischenspeichert. – blokeley

Verwandte Themen