Mam kilka warunków tuzin (np foo > bar
), które muszę ocenić na 1mm ~ wiersze o DataFrame
i najbardziej zwięzły sposobem zapisu jest zapisanie tych warunków jako listy łańcuchów i utworzenie DataFrame
wyników boolowskich (jeden wiersz na rekord x kolumna na warunek). (Wejście użytkownika jest nie oceniany.)kiedy używać DataFrame.eval() kontra pandas.eval eval() lub() Pythona
W pogoni za przedwczesne optymalizacji Próbuję ustalić, czy powinienem napisać te warunki oceny w DataFrame
(np df.eval("foo > bar")
lub po prostu zostawić go python jak w eval("df.foo > df.bar")
Według documentation on enhancing eval performance.
nie należy używać eval() dla prostych wyrażeń lub do wyrażenia udziałem małych DataFrames W rzeczywistości, eval() jest wiele rzędów Siła wolniejsza dla mniejszych wyrażeń/obiektów niż zwykły ol ' Python. Dobrą zasadą jest używanie funkcji eval() tylko wtedy, gdy masz DataFrame z ponad 10 000 wierszy.
Byłoby miło, aby móc użyć składni df.eval("foo > bar")
, bo moja lista będzie trochę bardziej czytelne, ale nigdy nie może znaleźć przypadek, w którym nie jest wolniejszy ocenić. W dokumentacji pokazano przykłady, gdzie pandas.eval()
jest szybszy niż python eval()
(który pasuje do mojego doświadczenia), ale żaden dla DataFrame.eval()
(który jest wymieniony jako "Eksperymentalne").
Na przykład DataFrame.eval()
jest jeszcze jasne, przegrany w nie proste wypowiedzi na duży-owski DataFrame
:
import pandas as pd
import numpy as np
import numexpr
import timeit
someDf = pd.DataFrame({'a':np.random.uniform(size=int(1e6)), 'b':np.random.uniform(size=int(1e6))})
%timeit -n100 someDf.eval("a**b - a*b > b**a - b/a") # DataFrame.eval() on notional expression
%timeit -n100 eval("someDf['a']**someDf['b'] - someDf['a']*someDf['b'] > someDf['b']**someDf['a'] - someDf['b']/someDf['a']")
%timeit -n100 pd.eval("someDf.a**someDf.b - someDf.a*someDf.b > someDf.b**someDf.a - someDf.b/someDf.a")
100 loops, best of 3: 29.9 ms per loop
100 loops, best of 3: 18.7 ms per loop
100 loops, best of 3: 15.4 ms per loop
Tak jest zaletą DataFrame.eval()
jedynie w uproszczeniu wejście, lub możemy zidentyfikować okoliczności gdzie używanie tej metody jest rzeczywiście szybsze?
Czy istnieją inne wytyczne dotyczące korzystania z których eval()
? (Jestem świadomy, że pandas.eval()
nie obsługuje kompletny zestaw operacji.)
pd.show_versions()
INSTALLED VERSIONS
------------------
commit: None
python: 3.5.1.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
byteorder: little
LC_ALL: None
LANG: en_US
pandas: 0.18.0
nose: 1.3.7
pip: 8.1.2
setuptools: 20.3
Cython: 0.23.4
numpy: 1.10.4
scipy: 0.17.0
statsmodels: None
xarray: None
IPython: 4.1.2
sphinx: 1.3.1
patsy: 0.4.0
dateutil: 2.5.3
pytz: 2016.2
blosc: None
bottleneck: 1.0.0
tables: 3.2.2
numexpr: 2.5
matplotlib: 1.5.1
openpyxl: 2.3.2
xlrd: 0.9.4
xlwt: 1.0.0
xlsxwriter: 0.8.4
lxml: 3.6.0
bs4: 4.4.1
html5lib: None
httplib2: None
apiclient: None
sqlalchemy: 1.0.12
pymysql: None
psycopg2: None
jinja2: 2.8
boto: 2.39.0
dzięki za aktualizację - nie widziałem żadnych problemów w Twojej "infrastrukturze". Myślę, że najlepszym podejściem jest przetestowanie prędkości tak, jak robiłeś to na swoich prawdziwych danych. Mógłbyś też napisać mały "tłumacz", który tłumaczyłby wyrażenia z 'df.eval()' na 'pd.eval()' składnia – MaxU
@MaxU to dobry pomysł, dziękuję ... właściwie po prostu wykryłem nazwy zmiennych i wstaw przed nimi "df". – C8H10N4O2
Polecam użyć składni 'df ['colname']', ponieważ jest to bezpieczniejsze - jeśli posiadasz _risky_ nazwy kolumn (zastrzeżone atrybuty Pythona, takie jak 'id', nazwy kolumn ze spacjami itp.) – MaxU