395 Stimmen

Was ist der effizienteste Weg, um Schleife durch dataframes mit Pandas?

Ich möchte meine eigenen komplexen Operationen auf Finanzdaten in Datenrahmen in sequenzieller Weise durchführen.

Ich verwende zum Beispiel die folgende CSV-Datei von MSFT Yahoo Finanzen :

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 gehe dann wie folgt vor:

#!/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? Angesichts der Fokus auf Geschwindigkeit in Pandas, würde ich davon ausgehen, dass es einige spezielle Funktion, um durch die Werte in einer Weise, die man auch den Index abruft (möglicherweise durch einen Generator, um speichereffizient zu sein) zu iterieren sein muss? df.iteritems iteriert leider nur spaltenweise.

4voto

Siehe das letzte Exemplar

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(round(time.time()-A,5))

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

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

C = []
A = time.time()
for r in range(len(t)):
    C.append((t.loc[r, 'a'], t.loc[r, 'b']))
B.append(round(time.time()-A,5))

C = []
A = time.time()
[C.append((x,y)) for x,y in zip(t['a'], t['b'])]
B.append(round(time.time()-A,5))
B

0.46424
0.00505
0.00245
0.09879
0.00209

3voto

JohnE Punkte 27183

Ich glaube, der einfachste und effizienteste Weg, um durch DataFrames zu schleifen, ist die Verwendung von numpy und numba. In diesem Fall kann die Schleifenbildung in vielen Fällen ungefähr so schnell sein wie vektorisierte Operationen. Wenn numba keine Option ist, ist einfaches numpy wahrscheinlich die nächstbeste Option. Wie bereits mehrfach erwähnt, sollte die Vektorisierung der Standard sein, aber diese Antwort berücksichtigt lediglich die effiziente Schleifenbildung, wenn die Entscheidung für eine Schleife getroffen wurde, aus welchem Grund auch immer.

Verwenden wir als Testfall das Beispiel aus der Antwort von @DSM zur Berechnung einer prozentualen Veränderung. Dies ist eine sehr einfache Situation und in der Praxis würde man keine Schleife schreiben, um sie zu berechnen, aber als solche bietet sie eine vernünftige Grundlage für die Zeitmessung von vektorisierten Ansätzen gegenüber Schleifen.

Richten wir die 4 Ansätze mit einem kleinen DataFrame ein, und wir werden sie weiter unten mit einem größeren Datensatz testen.

import pandas as pd
import numpy as np
import numba as nb

df = pd.DataFrame( { 'close':[100,105,95,105] } )

pandas_vectorized = df.close.pct_change()[1:]

x = df.close.to_numpy()
numpy_vectorized = ( x[1:] - x[:-1] ) / x[:-1]

def test_numpy(x):
    pct_chng = np.zeros(len(x))
    for i in range(1,len(x)):
        pct_chng[i] = ( x[i] - x[i-1] ) / x[i-1]
    return pct_chng

numpy_loop = test_numpy(df.close.to_numpy())[1:]

@nb.jit(nopython=True)
def test_numba(x):
    pct_chng = np.zeros(len(x))
    for i in range(1,len(x)):
        pct_chng[i] = ( x[i] - x[i-1] ) / x[i-1]
    return pct_chng

numba_loop = test_numba(df.close.to_numpy())[1:]

Und hier sind die Zeitangaben für einen DataFrame mit 100.000 Zeilen (die Zeitangaben wurden mit Jupyter's %timeit Funktion, zur besseren Lesbarkeit in einer zusammenfassenden Tabelle zusammengefasst):

pandas/vectorized   1,130 micro-seconds
numpy/vectorized      382 micro-seconds
numpy/looped       72,800 micro-seconds
numba/looped          455 micro-seconds

Zusammenfassung: für einfache Fälle, wie diesen, würden Sie mit (vektorisierte) Pandas für Einfachheit und Lesbarkeit und (vektorisierte) Numpy für Geschwindigkeit gehen. Wenn Sie wirklich eine Schleife verwenden müssen, tun Sie es in Numpy. Wenn numba verfügbar ist, kombinieren Sie es mit numpy für zusätzliche Geschwindigkeit. In diesem Fall ist numpy + numba fast so schnell wie vektorisierter numpy-Code.

Andere Details:

  • Nicht angezeigt werden verschiedene Optionen wie iterrows, itertuples usw., die um Größenordnungen langsamer sind und eigentlich nie verwendet werden sollten.
  • Die Zeiten hier sind ziemlich typisch: numpy ist schneller als pandas und vectorized ist schneller als Schleifen, aber das Hinzufügen von numba zu numpy wird numpy oft dramatisch beschleunigen.
  • Alles außer der Pandas-Option erfordert die Konvertierung der DataFrame-Spalte in ein Numpy-Array. Diese Umwandlung ist in den Zeitangaben enthalten.
  • Die Zeit für die Definition/Kompilierung der numpy/numba-Funktionen wurde nicht in die Zeitangaben einbezogen, ist aber im Allgemeinen eine vernachlässigbare Komponente der Zeitangaben für jeden großen Datenrahmen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X