2016-08-01 19 views
3

Gibt es eine schnelle Möglichkeit, die letzten N Zeilen einer CSV-Datei in Python zu lesen, mit numpy oder pandas?Lesen Sie die letzten N Zeilen einer CSV-Datei in Python mit numpy/pandas

  1. kann ich skip_header in numpy oder skiprow in pandas nicht tun, weil die Länge der Datei ändert, und ich würde die letzten N Zeilen immer brauchen.

  2. Ich weiß, ich kann reines Python verwenden, um Zeile für Zeile aus der letzten Zeile der Datei zu lesen, aber das wäre sehr langsam. Ich kann das tun, wenn ich muss, aber eine effizientere Art und Weise mit numpy oder pandas (die im Wesentlichen mit C ist) würde wirklich geschätzt werden.

Antwort

7

Mit einer kleinen 10-zeilige Testdatei I 2 Ansätze ausprobiert - das Ganze analysieren und die letzten N Zeilen auswählen, gegen alle Zeilen laden, aber nur analysieren die letzten N:

In [1025]: timeit np.genfromtxt('stack38704949.txt',delimiter=',')[-5:] 
1000 loops, best of 3: 741 µs per loop 

In [1026]: %%timeit 
     ...: with open('stack38704949.txt','rb') as f: 
     ...:  lines = f.readlines() 
     ...: np.genfromtxt(lines[-5:],delimiter=',') 

1000 loops, best of 3: 378 µs per loop 

Dies wurde als ein Duplikat von Efficiently Read last 'n' rows of CSV into DataFrame markiert. Die akzeptierte Antwort verwendete

from collections import deque 

und sammelte die letzten N Zeilen in dieser Struktur. Es verwendete auch StringIO, um die Zeilen dem Parser zuzuführen, was eine unnötige Komplikation ist. genfromtxt nimmt Input von allem, was es Linien gibt, so ist eine Liste von Linien in Ordnung.

In [1031]: %%timeit 
     ...: with open('stack38704949.txt','rb') as f: 
     ...:  lines = deque(f,5) 
     ...: np.genfromtxt(lines,delimiter=',') 

1000 loops, best of 3: 382 µs per loop 

Im Wesentlichen zur gleichen Zeit wie readlines und Scheibe.

deque kann einen Vorteil haben, wenn die Datei sehr groß ist, und es wird teuer, auf alle Zeilen zu hängen. Ich denke nicht, dass es jede Datei Lesezeit spart. Zeilen müssen immer noch einzeln gelesen werden.

Timings für die row_count gefolgt von skip_header Ansatz sind langsamer; Es erfordert das Lesen der Datei zweimal. skip_header muss immer noch Zeilen lesen.

In [1046]: %%timeit 
     ...: with open('stack38704949.txt',"r") as f: 
     ...:  ...:  reader = csv.reader(f,delimiter = ",") 
     ...:  ...:  data = list(reader) 
     ...:  ...:  row_count = len(data) 
     ...: np.genfromtxt('stack38704949.txt',skip_header=row_count-5,delimiter=',') 

The slowest run took 5.96 times longer than the fastest. This could mean that an intermediate result is being cached. 
1000 loops, best of 3: 760 µs per loop 

Für die Zwecke des Zählens Linien, die wir nicht brauchen csv.reader zu verwenden, obwohl es nicht viel mehr Zeit kosten erscheint.

In [1048]: %%timeit 
     ...: with open('stack38704949.txt',"r") as f: 
     ...: lines=f.readlines() 
     ...: row_count = len(data) 
     ...: np.genfromtxt('stack38704949.txt',skip_header=row_count-5,delimiter=',') 

1000 loops, best of 3: 736 µs per loop 
3

Option 1

Sie die gesamte Datei mit numpy.genfromtxt lesen können, es als numpy Array erhalten, und nehmen Sie die letzten N Zeilen:

a = np.genfromtxt('filename', delimiter=',') 
lastN = a[-N:] 

Option 2

Sie können eine ähnliche Sache mit der üblichen Datei lesen:

with open('filename') as f: 
    lastN = list(f)[-N:] 

aber dieses Mal erhalten Sie die Liste der letzten N Zeilen als Zeichenfolgen.

Option 3 - ohne die gesamte Datei in dem Speicher lesen

Wir verwenden eine Liste von höchstens N Artikeln jede Iteration der letzten N Zeilen zu halten:

lines = [] 
N = 10 
with open('csv01.txt') as f: 
    for line in f: 
     lines.append(line) 
     if len(lines) > 10: 
      lines.pop(0) 

Eine echte csv erfordert eine geringfügige Änderung:

import csv 
... 
with ... 
    for line in csv.reader(f): 
    ... 
2

Verwenden skiprows Parameter von pandasread_csv(), die tou gher part findet die Anzahl der Zeilen im csv. hier sind eine mögliche Lösung:

with open('filename',"r") as f: 
    reader = csv.reader(f,delimiter = ",") 
    data = list(reader) 
    row_count = len(data) 

df = pd.read_csv('filename', skiprows = row_count - N)