Pandas ist wirklich großartig, aber ich bin wirklich überrascht, wie ineffizient es ist, Werte von einem Pandas.DataFrame abzurufen. Im folgenden Spielzeugbeispiel ist sogar die DataFrame.iloc-Methode mehr als 100-mal langsamer als ein Wörterbuch.
Die Frage: Ist die Lektion hier nur, dass Wörterbücher der bessere Weg sind, um nach Werten zu suchen? Ja, ich verstehe, dass genau dafür sie gemacht wurden. Aber ich frage mich nur, ob mir etwas an der Leistung der DataFrame-Suche fehlt.
Mir ist klar, dass diese Frage mehr "Nachdenken" als "Fragen" ist, aber ich werde eine Antwort akzeptieren, die Einblicke oder Perspektiven bietet. Vielen Dank.
import timeit
setup = '''
import numpy, pandas
df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
dictionary = df.to_dict()
'''
f = ['value = dictionary[5][5]', 'value = df.loc[5, 5]', 'value = df.iloc[5, 5]']
for func in f:
print func
print min(timeit.Timer(func, setup).repeat(3, 100000))
Wert = Wörterbuch [5] [5]
0,130625009537
value = df.loc [5, 5]
19.4681699276
Wert = df.iloc [5, 5]
17.2575249672
quelle
df.to_dict()
keine Spalten, sondern Diktate verwendet. Wenndic = {x:df[x].values.tolist() for x in df}
Sie verwenden, erhalten Sie (auf meinem Computer) eine 25-fache Verbesserung beim Zugriff auf Spalten und einen 1,5-fach schnelleren Zeilenzugriff. so Wörterbuch ist schnellerEs scheint, dass der Leistungsunterschied jetzt viel geringer ist (0.21.1 - Ich habe vergessen, was die Version von Pandas im ursprünglichen Beispiel war). Nicht nur die Leistungslücke zwischen Wörterbuchzugriff und
.loc
reduziert (von etwa 335-mal auf 126-mal langsamer),loc
(iloc
) ist jetzt weniger als zweimal langsamer alsat
(iat
).In [1]: import numpy, pandas ...: ...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10])) ...: ...: dictionary = df.to_dict() ...: In [2]: %timeit value = dictionary[5][5] 85.5 ns ± 0.336 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) In [3]: %timeit value = df.loc[5, 5] 10.8 µs ± 137 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [4]: %timeit value = df.at[5, 5] 6.87 µs ± 64.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [5]: %timeit value = df.iloc[5, 5] 14.9 µs ± 114 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [6]: %timeit value = df.iat[5, 5] 9.89 µs ± 54.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [7]: print(pandas.__version__) 0.21.1
---- Originalantwort unten ----
+1 für die Verwendung
at
oderiat
für skalare Operationen. Beispiel-Benchmark:In [1]: import numpy, pandas ...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10])) ...: dictionary = df.to_dict() In [2]: %timeit value = dictionary[5][5] The slowest run took 34.06 times longer than the fastest. This could mean that an intermediate result is being cached 1000000 loops, best of 3: 310 ns per loop In [4]: %timeit value = df.loc[5, 5] 10000 loops, best of 3: 104 µs per loop In [5]: %timeit value = df.at[5, 5] The slowest run took 6.59 times longer than the fastest. This could mean that an intermediate result is being cached 100000 loops, best of 3: 9.26 µs per loop In [6]: %timeit value = df.iloc[5, 5] 10000 loops, best of 3: 98.8 µs per loop In [7]: %timeit value = df.iat[5, 5] The slowest run took 6.67 times longer than the fastest. This could mean that an intermediate result is being cached 100000 loops, best of 3: 9.58 µs per loop
Es scheint, dass using
at
(iat
) ungefähr zehnmal schneller ist alsloc
(iloc
).quelle
Ich bin auf das gleiche Problem gestoßen. Sie können verwenden
at
, um zu verbessern."Da die Indizierung mit [] viele Fälle behandeln muss (Single-Label-Zugriff, Slicing, Boolesche Indizierung usw.), ist der Aufwand etwas höher, um herauszufinden, wonach Sie fragen. Wenn Sie nur möchten Der schnellste Weg, auf einen Skalarwert zuzugreifen, besteht darin, die Methoden
at
und zuiat
verwenden, die in allen Datenstrukturen implementiert sind. "siehe offizielle Referenz http://pandas.pydata.org/pandas-docs/stable/indexing.html Kapitel "Schnelles Abrufen und Einstellen von Skalarwerten"
quelle
Ich denke, der schnellste Weg, auf eine Zelle zuzugreifen, ist
Beide sind schneller als (glaube ich)
quelle
at
schneller zu sein - 4,68 µs (at
) gegenüber 5,98 µs (get_values
). Ist auchat
viel flexibler, da Sie benannte Indizes verwenden können.Beim Zugriff auf die Datenrahmenzeile ist ein anderes Phänomen aufgetreten. Testen Sie dieses einfache Beispiel auf einem Datenrahmen mit etwa 10.000.000 Zeilen. Wörterbuch rockt.
def testRow(go): go_dict = go.to_dict() times = 100000 ot= time.time() for i in range(times): go.iloc[100,:] nt = time.time() print('for iloc {}'.format(nt-ot)) ot= time.time() for i in range(times): go.loc[100,2] nt = time.time() print('for loc {}'.format(nt-ot)) ot= time.time() for i in range(times): [val[100] for col,val in go_dict.iteritems()] nt = time.time() print('for dict {}'.format(nt-ot))
quelle