NumPy Datei mit Filterzeilen im laufenden Betrieb lesen

8

Ich habe eine große Anzahl von Zahlen in einer CSV-Datei geschrieben und muss nur eine Scheibe dieses Arrays laden. Konzeptionell möchte ich np.genfromtxt() aufrufen und dann das resultierende Array in Zeilen schneiden, aber

  1. Die Datei ist so groß, dass sie möglicherweise nicht in den RAM
  2. passt
  3. Die Anzahl der relevanten Zeilen ist möglicherweise klein, so dass nicht jede Zeile analysiert werden muss.

MATLAB hat die Funktion textscan() , die einen Dateideskriptor aufnehmen und nur einen Teil der Datei lesen kann. Gibt es so etwas in NumPy?

Vorläufig habe ich die folgende Funktion definiert, die nur die Zeilen liest, die die gegebene Bedingung erfüllen:

%Vor%

Es gibt mehrere Probleme mit dieser Lösung:

  • nicht allgemein: unterstützt nur den Gleitkommatyp, während genfromtxt die Typen erkennt, die von Spalte zu Spalte variieren können; auch fehlende Werte, Konverter, Überspringen usw.;
  • nicht effizient: Wenn die Bedingung schwierig ist, kann jede Zeile zweimal geparst werden, auch die verwendete Datenstruktur und Lesepufferung kann suboptimal sein;
  • erfordert das Schreiben von Code.

Gibt es eine Standardfunktion, die das Filtern implementiert, oder ein Gegenstück zu MATLABs textscan ?

    
Roman Shapovalov 01.02.2013, 11:56
quelle

3 Antworten

16

Ich kann mir zwei Ansätze vorstellen, die einige der gewünschten Funktionen bieten:

  1. Eine Datei entweder in Blöcken / oder in Schritten von n-Zeilen / etc. lesen:
    Sie können ein generator an numpy.genfromtxt übergeben sowie numpy.loadtxt . Auf diese Weise können Sie ein großes Dataset aus einem Textdateispeicher effizient laden, während Sie all die praktischen Syntaxanalysefunktionen der beiden Funktionen beibehalten.

  2. Daten nur aus Zeilen lesen, die einem Kriterium entsprechen, das als Regex ausgedrückt werden kann:
    Sie können numpy.fromregex verwenden und regular expression verwenden. zu genau definieren, welche Token von einer gegebenen Zeile in der Eingabedatei geladen werden sollen. Zeilen, die nicht mit dem Muster übereinstimmen, werden ignoriert.

Um die beiden Ansätze zu veranschaulichen, werde ich ein Beispiel aus meinem Forschungskontext verwenden.
Ich muss oft Dateien mit der folgenden Struktur laden:

%Vor%

Diese Dateien können riesig sein (GBs) und ich bin nur an den numerischen Daten interessiert. Alle Datenblöcke haben die gleiche Größe - 6 in diesem Beispiel - und sie sind immer durch zwei Zeilen getrennt. Das stride der Blöcke ist also 8 .

Mit dem ersten Ansatz:

Zuerst werde ich einen Generator definieren, der die unerwünschten Linien herausfiltert:

%Vor%

Dann öffne ich die Datei, erstelle einen filter_lines -generator (hier muss ich die stride kennen) und übergebe diesen Generator an genfromtxt :

%Vor%

Das funktioniert wie ein Kinderspiel. Beachten Sie, dass ich usecols verwenden kann, um die erste Spalte der Daten loszuwerden. Auf die gleiche Weise könnten Sie alle anderen Funktionen von genfromtxt verwenden, um die Typen zu erkennen, verschiedene Typen von Spalte zu Spalte, fehlende Werte, Konverter, etc.

In diesem Beispiel war data.shape (204000, 3) , während die ursprüngliche Datei aus 272000 lines bestand.

Hier wird die generator verwendet, um homogen gestreckte Linien zu filtern, aber man kann sich auch vorstellen, dass sie inhomogene Linienblöcke nach (einfachen) Kriterien ausfiltert.

Verwenden des zweiten Ansatzes:

Hier ist die regexp , die ich verwenden werde:

%Vor%

Gruppen - d. h. in () - definieren die Token, die aus einer gegebenen Zeile extrahiert werden sollen. Als nächstes führt fromregex den Job aus und ignoriert Zeilen, die nicht mit dem Muster übereinstimmen:

%Vor%

Das Ergebnis ist genau das gleiche wie beim ersten Ansatz.

    
Theodros Zelleke 09.02.2013, 20:29
quelle
1

Wenn Sie eine Liste von Typen übergeben (die Formatbedingung), einen try-Block verwenden und yield verwenden, um genfromtxt als Generator zu verwenden, sollten wir in der Lage sein, textscan() zu replizieren.

%Vor%

Bearbeiten: Ich habe den Ausnahmeblock vergessen. Es läuft jetzt in Ordnung, und Sie können GenFormtext als Generator verwenden (mit einem zufälligen CSV-Protokoll, das ich herumgesessen habe):

%Vor%

Ich sollte wahrscheinlich bemerken, dass ich zip verwende, um die Komma-Trennlinie und das formatSpec zusammenzufassen, das die beiden Listen auflöst (stoppt, wenn eine der Listen keine Elemente mehr hat), so dass wir sie gemeinsam durchlaufen können , eine Schleife vermeiden, die von len(line) oder etwas ähnlichem abhängt.

    
m.brindley 01.02.2013 12:49
quelle
0

Versuch, einen Kommentar zu OP zu demonstrieren.

%Vor%

Ausgabe

%Vor%     
sotapme 01.02.2013 14:52
quelle