2016-03-14 22 views
5

In Pandas kann ich einfach pandas.io.parser.read_csv("file.csv", nrows=10000) verwenden, um die ersten 10000 Zeilen einer CSV-Datei zu erhalten.Holen Sie sich die letzten 10000 Zeilen einer CSV-Datei

Aber weil meine CSV-Datei sehr groß ist und die letzten Zeilen relevanter sind als die ersten, würde ich gerne die letzten 10000 Zeilen lesen. Dies ist jedoch nicht so einfach, selbst wenn ich die Länge der Datei kenne, denn wenn ich die ersten 990000 Zeilen einer csv-Datei mit 1000000 Zeile überspringe, wird die erste Zeile, die den Dateikopf enthält, übersprungen. (header=0 wird gemessen, nachdem skiprows angelegt wird, so dass es auch nicht helfen.)

Wie erhalte ich die letzten 10000 Zeilen aus einer CSV-Datei mit einem Header in Zeile 0, vorzugsweise ohne die Länge der Datei in den Zeilen zu wissen ?

+0

Sind Sie auf einem Linux- oder OSX-System? Wenn ja, dann ist die Verwendung von 'tail -n 10000 file> file2' wahrscheinlich die einfachste ... – Carpetsmoker

+0

Wenn Sie auf die Idee von @Carpetsmoker tippen, können Sie' subprocess.call () ': P – Mai

+0

@Carpetsmoker aber er braucht auch einen Header. Es sollte als 'head -n 1 Datei> file2; tail -n 10000 Datei >> file2' –

Antwort

5

Sie können zunächst mit Ihrer Größe der Datei berechnen:

size = sum(1 for l in open('file.csv')) 

Dann nutzen skiprows mit range:

df = pd.read_csv('file.csv', skiprows=range(1, size - 10000)) 

EDIT

Als @ivan_pozdeev mit dieser Lösung erwähnt Sie müssen zweimal durchgehen. Ich habe versucht, ganze Datei mit Pandas zu lesen und dann tail Methode verwenden, aber diese Methode langsamer als vorgeschlagen.

Beispiel Datenrahmen:

pd.DataFrame(np.random.randn(1000000,3), columns=list('abc')).to_csv('file.csv') 

Zeit

def f1(): 
    size = sum(1 for l in open('file.csv')) 
    return pd.read_csv('file.csv', skiprows=range(1, size - 10000)) 

def f2(): 
    return pd.read_csv('file.csv').tail(10000) 

In [10]: %timeit f1() 
1 loop, best of 3: 1.8 s per loop 

In [11]: %timeit f2() 
1 loop, best of 3: 1.94 s per loop 
+0

Hinweis: Dies geht zweimal durch die gesamte Datei. Nicht, dass ich (bereitwillig) einen besseren Weg sehe ... –

+0

@ivan_pozdeev Ich dachte, dass mit 'pd.read_csv ('file.csv') .tail (10000)' es schneller sein wird, aber vom Timing ist es ein bisschen langsamer. –

+2

Mit 'tail' vermute ich, du liest zuerst _all_ die Daten in einen' DataFrame', dann nimmst du ein Stück. Dies ist nicht nur langsamer, sondern es besteht die Gefahr, dass der Arbeitsspeicher knapp wird. –

1

Der einzige Weg, genau die letzten N Zeilen zu nehmen ist as per Anton Protopopov, zunächst die gesamte Datei durchlaufen, das Zählen der Linien.

Aber für den nächsten Schritt, sie zu nehmen, kann die Optimierung (die tail der Fall ist) vorgenommen werden:

  • wie Sie gehen, am Ende speichern Offsets von Linien in einem Ringpuffer der Länge N. Dann Das älteste Element im Puffer ist der erforderliche Offset. Dann genügt ein f.seek() für das Dateiobjekt gemäß Working with 10+GB dataset in Python Pandas.

Eine viel schnellere Art und Weise, die nicht durch die gesamte Datei geht nicht enthalten wäre keine genaue Anzahl der Zeilen erfordern: von dem, was ich sehe, Sie brauchen nur eine beliebig große Menge. So können Sie:

  • erhalten eine grobe Schätzung des Offset Sie suchen müssen (zB Berechnung/Schätzung der durchschnittlichen Länge einer Linie)
  • dort suchen, dann zum nächsten (oder der previous) Zeilenumbruch

    Dies erfordert besondere Vorsicht, wenn Sie Daten mit eingebetteten Zeilenumbrüchen haben können: In diesem Fall gibt es keine narrensichere Möglichkeit zu erkennen, welche Anführungszeichen sich öffnen und welche schließen. Sie müssen Annahmen darüber machen, was können und was nicht innerhalb/außerhalb von Zitaten sein kann ...und wie weit man nach einem Zitat sucht, um herauszufinden, ob der Zeilenumbruch eingebettet ist!

0

Sie können versuchen, tail von Pandas, gibt es letzten n Zeilen

df.tail(10000) 
3

Mit @Anton Protopopov Beispieldatei. Das Einlesen eines Teils der Datei und des Headers in separaten Operationen ist viel billiger als das Lesen der gesamten Datei.

einfach direkt die letzten Zeilen lesen

In [22]: df = read_csv("file.csv", nrows=10000, skiprows=990001, header=None, index_col=0) 

In [23]: df 
Out[23]: 
       1   2   3 
0         
990000 -0.902507 -0.274718 1.155361 
990001 -0.591442 -0.318853 -0.089092 
990002 -1.461444 -0.070372 0.946964 
990003 0.608169 -0.076891 0.431654 
990004 1.149982 0.661430 0.456155 
...   ...  ...  ... 
999995 0.057719 0.370591 0.081722 
999996 0.157751 -1.204664 1.150288 
999997 -2.174867 -0.578116 0.647010 
999998 -0.668920 1.059817 -2.091019 
999999 -0.263830 -1.195737 -0.571498 

[10000 rows x 3 columns] 

Ganz schnell, dies zu tun

In [24]: %timeit read_csv("file.csv", nrows=10000, skiprows=990001, header=None, index_col=0) 
1 loop, best of 3: 262 ms per loop 

Ziemlich billig, die Länge der Datei a-priori

In [25]: %timeit sum(1 for l in open('file.csv')) 
10 loops, best of 3: 104 ms per loop 

lesen, um festzustellen, die Kopfzeile

In [26]: df.columns = read_csv('file.csv', header=0, nrows=1, index_col=0).columns 

In [27]: df 
Out[27]: 
       a   b   c 
0         
990000 -0.902507 -0.274718 1.155361 
990001 -0.591442 -0.318853 -0.089092 
990002 -1.461444 -0.070372 0.946964 
990003 0.608169 -0.076891 0.431654 
990004 1.149982 0.661430 0.456155 
...   ...  ...  ... 
999995 0.057719 0.370591 0.081722 
999996 0.157751 -1.204664 1.150288 
999997 -2.174867 -0.578116 0.647010 
999998 -0.668920 1.059817 -2.091019 
999999 -0.263830 -1.195737 -0.571498 

[10000 rows x 3 columns] 
Verwandte Themen