2016-08-02 28 views
9

Ben bir DataFrame ~ 1 MM satırlar üzerinde değerlendirmek gereken birkaç düzine (örneğin, foo > bar) var ve en özlü Yazmanın yolu, bu koşulları dizelerin bir listesi olarak saklamak ve bir DataFrame boolean sonucu (her kayıtta bir satır x bir sütun) oluşturmaktır. (Kullanıcı girişi değil değerlendirilmektedir budur.) Prematüre optimizasyonu için arayışı içinde ne zaman DataFrame.eval() versus pandas.eval() veya python eval()

, ben DataFrame içinde değerlendirme için bu koşulları yazmak gerektiğini belirlemek çalışıyorum (örn df.eval("foo > bar") ya da sadece eval("df.foo > df.bar") gibi piton bırakın

documentation on enhancing eval performance göre:.arasında

basit ifadeler için ya da küçük DataFrames içeren ifadeler için eval() kullanmamalısınız Aslında, eval() birçok siparişleri Python'dan daha küçük ifadeler/nesneler içinbüyüklük daha yavaş. İyi bir kural, yalnızca 10,000'den fazla satır içeren bir DataFrame'iniz olduğunda eval() öğesini kullanmaktır. Benim liste biraz daha okunabilir olacaktır çünkü

df.eval("foo > bar") sözdizimi kullanabilmek için iyi olurdu, ama şimdiye kadar bunun değerlendirmek değil yavaş bir durumla bulamıyor. Belgeler, pandas.eval()'un python eval()'dan (ki bu benim deneyimlerimle eşleşir) daha hızlı olduğu örnekleri gösterir, ancak hiçbiri DataFrame.eval() ('Deneysel' olarak listelenir) için geçerli değildir.

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 

Yani DataFrame.eval() faydası sadece girişini basitleştirilmesi olduğunu, yoksa şartlar belirleyebilir: Örneğin

, DataFrame.eval() hala large-ish DataFrame üzerinde değil-basit ifadede açık bir kaybeden Bu yöntemi kullanarak nerede daha hızlı?

Hangi eval() kullanılıp kullanılmayacağı konusunda başka yönergeler var mı? sadece giriş basitleştirilmesi içinde)

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 
+0

Güncelleme için teşekkürler - "altyapı" nızda herhangi bir sorun göremedim. En iyi yaklaşımın, gerçek verilerinizde yaptığınız gibi hızı test ettiğini düşünüyorum. Ayrıca, df.eval() 'dan' pd.eval() 'sözdizimine – MaxU

+0

@MaxU'dan ifadeleri çeviren küçük bir" çevirmen "yazabilirsiniz, bu iyi bir fikirdir ... temelde sadece değişken isimleri algılayacağım ve önlerine 'df.' ekleyin. – C8H10N4O2

+4

'df ['colname']' sözdizimini, daha güvenli olduğu şekilde kullanmanızı öneririm - eğer bir _risky_ sütun iseniz (ayrılmış olan Python öznitelikleri, id gibi boşluk alanları, sütun adları vb.) – MaxU

cevap

3

Yani DataFrame.eval (yararı olduğu (I. pandas.eval() operasyonların tam set desteklemediği farkındayım) veya bu kullanarak nereye koşullar belirleyebilir yöntem aslında daha hızlı mı?

_eval() pd.eval için sadece bir takma addır
def eval(self, expr, inplace=None, **kwargs): 

    inplace = validate_bool_kwarg(inplace, 'inplace') 
    resolvers = kwargs.pop('resolvers', None) 
    kwargs['level'] = kwargs.pop('level', 0) + 1 
    if resolvers is None: 
     index_resolvers = self._get_index_resolvers() 
     resolvers = dict(self.iteritems()), index_resolvers 
    if 'target' not in kwargs: 
     kwargs['target'] = self 
    kwargs['resolvers'] = kwargs.get('resolvers',()) + tuple(resolvers) 
    return _eval(expr, inplace=inplace, **kwargs) 

(:

DataFrame.eval() için source code aslında sadece() pd.eval geçirilecek olan bağımsız değişkenleri yarattığını göstermektedir) modülün başında ithal edilen:

from pandas.core.computation.eval import eval as _eval 

Yani df.eval() ile yapabileceğiniz bir şey, sen pd.eval() yapabileceğini + bazı şeyleri ayarlamak için birkaç ekstra satır. Şu anda durduğu gibi, df.eval() asla pd.eval()'dan daha hızlı değildir.Ancak bu, df.eval()'un pd.eval() kadar iyi olduğu, ancak yazmanın daha uygun olduğu durumlar olamayacağı anlamına gelmez.

Ancak %prun büyü ile uğraşırken sonra df._get_index_resolvers() için df.eval() tarafından çağrı df.eval() yönteme zaman adil bit ekler anlaşılmaktadır. Nihayetinde, _get_index_resolvers(), numpy.ndarray numaralı .copy() yöntemini çağırır ve bu da yavaşlama olaylarını sona erdirir. Bu arada, pd.eval() bir noktada numpy.ndarray.copy()'u arar, ancak ihmal edilebilir bir süre alır (makinemde en azından).

Uzun lafın kısası, df.eval() çünkü sadece pd.eval() ekstra adımlarla var kaputun altında daha yavaş pd.eval() olma eğiliminde olduğunu görünür ve bu adımlar olmayan önemsizdir.