it-swarm.com.de

Was ist der effizienteste Weg, um Datenrahmen mit Pandas zu durchlaufen?

Ich möchte meine eigenen komplexen Operationen für Finanzdaten in Datenrahmen nacheinander ausführen.

Zum Beispiel verwende ich die folgende MSFT CSV-Datei aus Yahoo Finance :

Date,Open,High,Low,Close,Volume,Adj Close
2011-10-19,27.37,27.47,27.01,27.13,42880000,27.13
2011-10-18,26.94,27.40,26.80,27.31,52487900,27.31
2011-10-17,27.11,27.42,26.85,26.98,39433400,26.98
2011-10-14,27.31,27.50,27.02,27.27,50947700,27.27

....

Ich mache dann folgendes:

#!/usr/bin/env python
from pandas import *

df = read_csv('table.csv')

for i, row in enumerate(df.values):
    date = df.index[i]
    open, high, low, close, adjclose = row
    #now perform analysis on open/close based on date, etc..

Ist das der effizienteste Weg? In Anbetracht des Fokus auf Geschwindigkeit in Pandas würde ich annehmen, dass es eine spezielle Funktion geben muss, um die Werte in einer Weise zu durchlaufen, dass man auch den Index abruft (möglicherweise durch einen Generator, um speichereffizient zu sein)? df.iteritems iteriert leider nur spaltenweise.

299
Muppet

Die neuesten Versionen von pandas enthalten jetzt eine integrierte Funktion zum Durchlaufen von Zeilen.

for index, row in df.iterrows():

    # do some logic here

Oder, wenn du es schneller haben willst, benutze itertuples()

Der Vorschlag von unutbu, numpy-Funktionen zu verwenden, um das Iterieren über Zeilen zu vermeiden, führt jedoch zum schnellsten Code.

348
Nick Crawford

Pandas basiert auf NumPy-Arrays. Der Schlüssel zur Beschleunigung von NumPy-Arrays besteht darin, Ihre Operationen auf einmal für das gesamte Array auszuführen, niemals Zeile für Zeile oder Element für Element.

Wenn zum Beispiel close ein 1-d-Array ist und Sie möchten, dass sich der Prozentsatz im Tagesverlauf ändert,

pct_change = close[1:]/close[:-1]

Dadurch wird das gesamte Array der prozentualen Änderungen als eine Anweisung anstelle von berechnet

pct_change = []
for row in close:
    pct_change.append(...)

Versuchen Sie also, die Python -Schleife for i, row in enumerate(...) vollständig zu vermeiden, und überlegen Sie, wie Sie Ihre Berechnungen mit Operationen auf dem gesamten Array (oder Datenrahmen) als Ganzes und nicht zeilenweise durchführen.

149
unutbu

Wie bereits erwähnt, ist das Objekt pandas am effizientesten, wenn das gesamte Array auf einmal verarbeitet wird. Für diejenigen, die wirklich einen pandas DataFrame durchlaufen müssen, um etwas wie mich auszuführen, habe ich jedoch mindestens drei Möglichkeiten gefunden, dies zu tun. Ich habe einen kurzen Test durchgeführt, um festzustellen, welcher der drei am wenigsten Zeit kostet.

t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
B = []
C = []
A = time.time()
for i,r in t.iterrows():
    C.append((r['a'], r['b']))
B.append(time.time()-A)

C = []
A = time.time()
for ir in t.itertuples():
    C.append((ir[1], ir[2]))    
B.append(time.time()-A)

C = []
A = time.time()
for r in Zip(t['a'], t['b']):
    C.append((r[0], r[1]))
B.append(time.time()-A)

print B

Ergebnis:

[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]

Dies ist wahrscheinlich nicht der beste Weg, um den Zeitverbrauch zu messen, aber es ist schnell für mich.

Hier sind einige Vor- und Nachteile IMHO:

  • .iterrows (): gibt Index- und Zeilenelemente in separaten Variablen zurück, jedoch deutlich langsamer
  • .itertuples (): schneller als .iterrows (), aber Index zusammen mit Zeilenelementen zurückgeben, ir [0] ist der Index
  • Zip: am schnellsten, aber kein Zugriff auf den Index der Zeile
85
Richard Wong

Sie können die Zeilen durchlaufen, indem Sie die Iteritems transponieren und dann aufrufen:

for date, row in df.T.iteritems():
   # do some logic here

In diesem Fall bin ich mir der Effizienz nicht sicher. Um die bestmögliche Leistung in einem iterativen Algorithmus zu erzielen, sollten Sie das Schreiben in Cython untersuchen, damit Sie Folgendes tun können:

def my_algo(ndarray[object] dates, ndarray[float64_t] open,
            ndarray[float64_t] low, ndarray[float64_t] high,
            ndarray[float64_t] close, ndarray[float64_t] volume):
    cdef:
        Py_ssize_t i, n
        float64_t foo
    n = len(dates)

    for i from 0 <= i < n:
        foo = close[i] - open[i] # will be extremely fast

Ich würde empfehlen, den Algorithmus zunächst in reinem Python zu schreiben. Vergewissern Sie sich, dass er funktioniert, und prüfen Sie, wie schnell er ist. Wenn er nicht schnell genug ist, konvertieren Sie solche Dinge mit minimalem Aufwand in Cython, um etwas zu erhalten, das ungefähr so ​​ist schnell wie handcodiertes C/C++.

72
Wes McKinney

Sie haben drei Möglichkeiten:

Nach Index (am einfachsten):

>>> for index in df.index:
...     print ("df[" + str(index) + "]['B']=" + str(df['B'][index]))

Mit iterrows (meistens verwendet):

>>> for index, row in df.iterrows():
...     print ("df[" + str(index) + "]['B']=" + str(row['B']))

Mit itertuples (am schnellsten):

>>> for row in df.itertuples():
...     print ("df[" + str(row.Index) + "]['B']=" + str(row.B))

Drei Optionen zeigen ungefähr Folgendes an:

df[0]['B']=125
df[1]['B']=415
df[2]['B']=23
df[3]['B']=456
df[4]['B']=189
df[5]['B']=456
df[6]['B']=12

Quelle: neural-networks.io

27
Fifi

Ich habe iterrows ausgecheckt, nachdem ich Nick Crawfords Antwort bemerkt hatte, aber festgestellt, dass es (Index, Serie) Tupel liefert. Ich bin mir nicht sicher, welches für Sie am besten geeignet ist, aber ich habe die itertuples -Methode für mein Problem verwendet, die Tupel (index, row_value1 ...) liefert.

Es gibt auch iterkv, das Tupel (Spalte, Reihe) durchläuft.

25
beardc

Als kleine Ergänzung können Sie auch anwenden, wenn Sie eine komplexe Funktion haben, die Sie auf eine einzelne Spalte anwenden:

http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.apply.html

df[b] = df[a].apply(lambda col: do stuff with col here)
20
Carst

Wie @ joris hervorhob, ist iterrows viel langsamer als itertuples und itertuples ist ungefähr 100-mal schneller als iterrows, und ich habe die Geschwindigkeit von getestet Beide Methoden in einem DataFrame mit 5027505-Datensätzen haben das Ergebnis iterrows, 1200it/s und itertuples 120000it/s.

Wenn Sie itertuples verwenden, beachten Sie, dass jedes Element in der for-Schleife ein namedtuple ist. Um den Wert in jeder Spalte zu erhalten, können Sie sich auf den folgenden Beispielcode beziehen

>>> df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]},
                      index=['a', 'b'])
>>> df
   col1  col2
a     1   0.1
b     2   0.2
>>> for row in df.itertuples():
...     print(row.col1, row.col2)
...
1, 0.1
2, 0.2
8
GoingMyWay

Der schnellste Weg, über einen Datenrahmen zu iterieren, besteht darin, entweder über df.values (wie Sie es tun) oder durch separaten Zugriff auf jede Spalte df.column_name.values auf die zugrunde liegende numpy ndarray zuzugreifen. Da Sie auch auf den Index zugreifen möchten, können Sie dafür df.index.values verwenden.

index = df.index.values
column_of_interest1 = df.column_name1.values
...
column_of_interestk = df.column_namek.values

for i in range(df.shape[0]):
   index_value = index[i]
   ...
   column_value_k = column_of_interest_k[i]

Nicht pythonisch? Sicher. Aber schnell.

Wenn Sie mehr Saft aus der Schleife pressen möchten, sollten Sie Cython . Mit Cython können Sie enorme Geschwindigkeitssteigerungen erzielen (10x-100x). Für maximale Performance check Speicheransichten für Cython .

6
Vlad

Ein weiterer Vorschlag wäre, groupby mit vektorisierten Berechnungen zu kombinieren, wenn Teilmengen der Zeilen Merkmale gemeinsam haben, die dies zulassen.

5
JoeCondron