pandas 0.23 - 23. Enhancing Performance

प्रदर्शन बढ़ाना




pandas

प्रदर्शन बढ़ाना

ट्यूटोरियल के इस भाग में, हम जांच करेंगे कि तीन अलग-अलग तकनीकों का उपयोग करके पांडा DataFrames पर काम करने वाले कुछ कार्यों को कैसे तेज किया DataFrames : pandas.eval() , pandas.eval() और pandas.eval() । जब हम DataFrame पर एक परीक्षण फ़ंक्शन ऑपरेटिंग रो-वार पर DataFrame और DataFrame उपयोग करते हैं, तो हम ~ 200 की गति में सुधार DataFrame pandas.eval() का उपयोग करके हम ~ 2 के आदेश से एक राशि को गति देंगे।

साइथन (पांडा के लिए सी एक्सटेंशन लेखन)

कई उपयोग मामलों के लिए शुद्ध पायथन और न्यूमपी में पांडा लिखना पर्याप्त है। कुछ कम्प्यूटेशनल रूप से भारी अनुप्रयोगों में, cython लिए काम करने से cython गति प्राप्त करना संभव हो सकता है।

यह ट्यूटोरियल मानता है कि आपने पायथन में जितना संभव हो उतना कम रिफ्लेक्ट किया है, उदाहरण के लिए लूप को हटाने की कोशिश करके और न्यूम्य वर्चुअलाइजेशन का उपयोग करके। यह हमेशा पहले पायथन में अनुकूलन के लायक है।

यह ट्यूटोरियल धीमी गति से गणना करने के लिए "विशिष्ट" प्रक्रिया के माध्यम से चलता है। हम साइथन प्रलेखन से एक उदाहरण का उपयोग करते हैं, लेकिन पांडा के संदर्भ में। हमारा अंतिम साइटोनाइज्ड समाधान शुद्ध पायथन समाधान की तुलना में लगभग 100 गुना तेज है।

शुद्ध अजगर

हमारे पास एक DataFrame है, जिसे हम एक फ़ंक्शन पंक्ति-वार लागू करना चाहते हैं।

In [1]: df = pd.DataFrame({'a': np.random.randn(1000),
   ...:                    'b': np.random.randn(1000),
   ...:                    'N': np.random.randint(100, 1000, (1000)),
   ...:                    'x': 'x'})
   ...: 

In [2]: df
Out[2]: 
            a         b    N  x
0    0.469112 -0.218470  585  x
1   -0.282863 -0.061645  841  x
2   -1.509059 -0.723780  251  x
3   -1.135632  0.551225  972  x
4    1.212112 -0.497767  181  x
5   -0.173215  0.837519  458  x
6    0.119209  1.103245  159  x
..        ...       ...  ... ..
993  0.131892  0.290162  190  x
994  0.342097  0.215341  931  x
995 -1.512743  0.874737  374  x
996  0.933753  1.120790  246  x
997 -0.308013  0.198768  157  x
998 -0.079915  1.757555  977  x
999 -1.010589 -1.115680  770  x

[1000 rows x 4 columns]

यहाँ शुद्ध अजगर में समारोह है:

In [3]: def f(x):
   ...:     return x * (x - 1)
   ...: 

In [4]: def integrate_f(a, b, N):
   ...:     s = 0
   ...:     dx = (b - a) / N
   ...:     for i in range(N):
   ...:         s += f(a + i * dx)
   ...:     return s * dx
   ...: 

हम apply (पंक्ति-वार) का उपयोग करके अपना परिणाम प्राप्त करते हैं:

In [7]: %timeit df.apply(lambda x: integrate_f(x['a'], x['b'], x['N']), axis=1)
10 loops, best of 3: 174 ms per loop

लेकिन स्पष्ट रूप से यह हमारे लिए पर्याप्त उपवास नहीं है। आइए एक नज़र डालते हैं और देखते हैं कि इस ऑपरेशन के दौरान कहाँ समय बिताया जाता है ( प्रून आइपीथॉन मैजिक फंक्शन का उपयोग करके)

In [5]: %prun -l 4 df.apply(lambda x: integrate_f(x['a'], x['b'], x['N']), axis=1)
         671713 function calls (666693 primitive calls) in 0.246 seconds

   Ordered by: internal time
   List reduced from 214 to 4 due to restriction <4>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1000    0.121    0.000    0.177    0.000 <ipython-input-4-c2a74e076cf0>:1(integrate_f)
   552423    0.056    0.000    0.056    0.000 <ipython-input-3-c138bdd570e3>:1(f)
     3000    0.008    0.000    0.045    0.000 base.py:3090(get_value)
        1    0.006    0.006    0.245    0.245 {pandas._libs.reduction.reduce}

अब तक अधिकांश समय integrate_f f या f अंदर ही व्यतीत होता है, इसलिए हम इन दोनों कार्यों को सायंटोनाइजिंग करने के अपने प्रयासों पर ध्यान केंद्रित करेंगे।

ध्यान दें

पायथन 2 में अपने जनरेटर समकक्ष ( xrange ) के साथ range को बदलने का मतलब होगा कि range रेखा गायब हो जाएगी। पायथन 3 range में पहले से ही एक जनरेटर है।

सायन साइथन

पहले हम साइथॉन जादू समारोह आयात करने की आवश्यकता करने जा रहे हैं ipython:

In [6]: %load_ext Cython

अब, सिथॉन पर हमारे कार्यों को कॉपी करें जैसा कि है (प्रत्यय फ़ंक्शन संस्करणों के बीच अंतर करने के लिए यहां है):

In [7]: %%cython
   ...: def f_plain(x):
   ...:     return x * (x - 1)
   ...: def integrate_f_plain(a, b, N):
   ...:     s = 0
   ...:     dx = (b - a) / N
   ...:     for i in range(N):
   ...:         s += f_plain(a + i * dx)
   ...:     return s * dx
   ...: 

ध्यान दें

यदि आपको अपने ipython में उपरोक्त चिपकाने में समस्या हो रही है, तो आपको सेल मैजिक के साथ खेलने के लिए पेस्ट के लिए ब्लीडिंग एज ipython का उपयोग करना पड़ सकता है।

In [4]: %timeit df.apply(lambda x: integrate_f_plain(x['a'], x['b'], x['N']), axis=1)
10 loops, best of 3: 85.5 ms per loop

पहले से ही इसने तीसरी बार मुंडन किया है, एक साधारण कॉपी और पेस्ट के लिए बहुत बुरा नहीं है।

प्रकार जोड़ रहा है

हम केवल जानकारी प्रदान करके एक और बड़ा सुधार प्राप्त करते हैं:

In [8]: %%cython
   ...: cdef double f_typed(double x) except? -2:
   ...:     return x * (x - 1)
   ...: cpdef double integrate_f_typed(double a, double b, int N):
   ...:     cdef int i
   ...:     cdef double s, dx
   ...:     s = 0
   ...:     dx = (b - a) / N
   ...:     for i in range(N):
   ...:         s += f_typed(a + i * dx)
   ...:     return s * dx
   ...: 
In [4]: %timeit df.apply(lambda x: integrate_f_typed(x['a'], x['b'], x['N']), axis=1)
10 loops, best of 3: 20.3 ms per loop

अब हम बात कर रहे हैं! यह मूल अजगर कार्यान्वयन की तुलना में अब दस गुना अधिक तेज है, और हमने वास्तव में कोड को संशोधित नहीं किया है। चलिए एक और नज़र डालते हैं कि समय क्या खा रहा है:

In [9]: %prun -l 4 df.apply(lambda x: integrate_f_typed(x['a'], x['b'], x['N']), axis=1)
         119288 function calls (114268 primitive calls) in 0.055 seconds

   Ordered by: internal time
   List reduced from 211 to 4 due to restriction <4>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     3000    0.006    0.000    0.036    0.000 base.py:3090(get_value)
     9117    0.004    0.000    0.008    0.000 {built-in method builtins.getattr}
     3000    0.004    0.000    0.041    0.000 series.py:764(__getitem__)
        1    0.003    0.003    0.054    0.054 {pandas._libs.reduction.reduce}

Ndarray का उपयोग करना

यह श्रृंखला बुला रहा है ... बहुत! यह प्रत्येक पंक्ति से एक श्रृंखला बना रहा है, और अनुक्रमणिका और श्रृंखला (प्रत्येक पंक्ति के लिए तीन बार) दोनों से टिंग प्राप्त करें। पाइथन में फंक्शन कॉल्स महंगे हैं, इसलिए शायद हम इन्हें लागू करने वाले हिस्से को साइंटिफाई करके कम कर सकते हैं।

ध्यान दें

अब हम साइथॉन फ़ंक्शन में ndarrays पास कर रहे हैं, सौभाग्य से Cython NumPy के साथ बहुत अच्छी तरह से खेलता है।

In [10]: %%cython
   ....: cimport numpy as np
   ....: import numpy as np
   ....: cdef double f_typed(double x) except? -2:
   ....:     return x * (x - 1)
   ....: cpdef double integrate_f_typed(double a, double b, int N):
   ....:     cdef int i
   ....:     cdef double s, dx
   ....:     s = 0
   ....:     dx = (b - a) / N
   ....:     for i in range(N):
   ....:         s += f_typed(a + i * dx)
   ....:     return s * dx
   ....: cpdef np.ndarray[double] apply_integrate_f(np.ndarray col_a, np.ndarray col_b, np.ndarray col_N):
   ....:     assert (col_a.dtype == np.float and col_b.dtype == np.float and col_N.dtype == np.int)
   ....:     cdef Py_ssize_t i, n = len(col_N)
   ....:     assert (len(col_a) == len(col_b) == n)
   ....:     cdef np.ndarray[double] res = np.empty(n)
   ....:     for i in range(len(col_a)):
   ....:         res[i] = integrate_f_typed(col_a[i], col_b[i], col_N[i])
   ....:     return res
   ....: 

क्रियान्वयन सरल है, यह हमारे एकीकृत_फ्लिप्ड को लागू करने और इसे शून्य में रखने के साथ, पंक्तियों के ऊपर शून्य और छोरों की एक सरणी बनाता है।

चेतावनी

आप एक Series सीधे सिडरॉन फ़ंक्शन के ndarray टाइप किए गए पैरामीटर के रूप में पास नहीं कर सकते। इसके बजाय Series के .values विशेषता का उपयोग करके वास्तविक .values पास करें। कारण यह है कि साइथॉन की परिभाषा एक ndarray के लिए विशिष्ट है न कि पारित Series

तो, यह मत करो:

apply_integrate_f(df['a'], df['b'], df['N'])

बल्कि, अंतर्निहित .values प्राप्त करने के लिए .values का उपयोग करें:

apply_integrate_f(df['a'].values, df['b'].values, df['N'].values)

ध्यान दें

इस तरह की लपटें पायथन में बेहद धीमी गति से होती हैं, लेकिन साइथॉन में न्यूपी सरणियों पर लूपिंग तेज है

In [4]: %timeit apply_integrate_f(df['a'].values, df['b'].values, df['N'].values)
1000 loops, best of 3: 1.25 ms per loop

हमने एक और बड़ा सुधार प्राप्त किया है। आइए फिर से जाँच करें कि समय कहाँ बिताया गया है:

In [11]: %prun -l 4 apply_integrate_f(df['a'].values, df['b'].values, df['N'].values)
         215 function calls in 0.001 seconds

   Ordered by: internal time
   List reduced from 55 to 4 due to restriction <4>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.001    0.001    0.001    0.001 {built-in method _cython_magic_20a45bf86d2a48d5dc2e7ff1cb491989.apply_integrate_f}
        3    0.000    0.000    0.000    0.000 internals.py:4137(iget)
        1    0.000    0.000    0.001    0.001 {built-in method builtins.exec}
        3    0.000    0.000    0.000    0.000 frame.py:2664(__getitem__)

जैसा कि कोई उम्मीद कर सकता है, समय का अधिकांश हिस्सा अब apply_integrate_f में बिताया गया है, इसलिए यदि हम अब और अधिक क्षमता बनाना चाहते हैं तो हमें अपने प्रयासों को यहां केंद्रित करना चाहिए।

अधिक उन्नत तकनीकें

अभी भी सुधार की उम्मीद है। यहां कुछ और उन्नत साइथन तकनीकों का उपयोग करने का एक उदाहरण दिया गया है:

In [12]: %%cython
   ....: cimport cython
   ....: cimport numpy as np
   ....: import numpy as np
   ....: cdef double f_typed(double x) except? -2:
   ....:     return x * (x - 1)
   ....: cpdef double integrate_f_typed(double a, double b, int N):
   ....:     cdef int i
   ....:     cdef double s, dx
   ....:     s = 0
   ....:     dx = (b - a) / N
   ....:     for i in range(N):
   ....:         s += f_typed(a + i * dx)
   ....:     return s * dx
   ....: @cython.boundscheck(False)
   ....: @cython.wraparound(False)
   ....: cpdef np.ndarray[double] apply_integrate_f_wrap(np.ndarray[double] col_a, np.ndarray[double] col_b, np.ndarray[int] col_N):
   ....:     cdef int i, n = len(col_N)
   ....:     assert len(col_a) == len(col_b) == n
   ....:     cdef np.ndarray[double] res = np.empty(n)
   ....:     for i in range(n):
   ....:         res[i] = integrate_f_typed(col_a[i], col_b[i], col_N[i])
   ....:     return res
   ....: 
In [4]: %timeit apply_integrate_f_wrap(df['a'].values, df['b'].values, df['N'].values)
1000 loops, best of 3: 987 us per loop

यहां तक ​​कि तेजी से, इस चेतावनी के साथ कि हमारे साइथॉन कोड में एक बग (उदाहरण के लिए एक ऑफ-बाय-वन एरर) सेगफॉल्ट का कारण हो सकता है क्योंकि मेमोरी एक्सेस की जांच नहीं की जाती है। boundscheck - boundscheck और boundscheck बारे में अधिक जानकारी के लिए, संकलक निर्देशों पर boundscheck डॉक्स देखें।

Numba का उपयोग करना

साइथन कोड को सांख्यिकीय रूप से संकलित करने का एक हालिया विकल्प, गतिशील जीट-कंपाइलर , नुम्बा का उपयोग करना है।

नुम्बा आपको सीधे पाइथन में लिखे गए उच्च प्रदर्शन कार्यों के साथ अपने अनुप्रयोगों को गति देने की शक्ति देता है। कुछ एनोटेशन के साथ, सरणी-उन्मुख और गणित-भारी पाइथन कोड को मूल मशीन निर्देशों के लिए संकलित किया जा सकता है, जो C या C ++ और फोरट्रान के समान है, भाषाओं या पायथन दुभाषियों को स्विच किए बिना।

Numba आयात समय, रनटाइम या स्टेटिक रूप से (शामिल pycc टूल का उपयोग करके) LLVM कंपाइलर इन्फ्रास्ट्रक्चर का उपयोग करके अनुकूलित मशीन कोड उत्पन्न करके काम करता है। Numba CPU या GPU हार्डवेयर पर चलने के लिए Python के संकलन का समर्थन करता है, और इसे Python वैज्ञानिक सॉफ़्टवेयर स्टैक के साथ एकीकृत करने के लिए डिज़ाइन किया गया है।

ध्यान दें

आपको Numba इंस्टॉल करना होगा। यह conda साथ आसान है, का उपयोग करके: conda install numba , miniconda का उपयोग करके स्थापित करना देखें

ध्यान दें

Numba संस्करण 0.20 के रूप में, पांडा की वस्तुओं को सीधे Numba- संकलित कार्यों में पारित नहीं किया जा सकता है। इसके बजाय, किसी को नुम्बा-संकलित फ़ंक्शन के लिए नीचे दिखाए गए अनुसार pandas ऑब्जेक्ट को अंतर्निहित NumPy सरणी को पास करना होगा।

जीत

हम प्रदर्शित करते हैं कि किस तरह से Numba का उपयोग समय-समय पर हमारे कोड को संकलित करने के लिए किया जाता है। हम बस ऊपर से प्लेन पायथन कोड लेते हैं और @jit डेकोरेटर के साथ एनोटेट करते हैं।

import numba

@numba.jit
def f_plain(x):
   return x * (x - 1)

@numba.jit
def integrate_f_numba(a, b, N):
   s = 0
   dx = (b - a) / N
   for i in range(N):
       s += f_plain(a + i * dx)
   return s * dx

@numba.jit
def apply_integrate_f_numba(col_a, col_b, col_N):
   n = len(col_N)
   result = np.empty(n, dtype='float64')
   assert len(col_a) == len(col_b) == n
   for i in range(n):
      result[i] = integrate_f_numba(col_a[i], col_b[i], col_N[i])
   return result

def compute_numba(df):
   result = apply_integrate_f_numba(df['a'].values, df['b'].values, df['N'].values)
   return pd.Series(result, index=df.index, name='result')

ध्यान दें कि हम सीधे Numba फ़ंक्शन में NumPy सरणियों को पास करते हैं। compute_numba केवल एक रैपर है जो पंडों की वस्तुओं को पारित / वापस करके एक अच्छा इंटरफ़ेस प्रदान करता है।

In [4]: %timeit compute_numba(df)
1000 loops, best of 3: 798 us per loop

इस उदाहरण में, नुम्बा का उपयोग साइथन की तुलना में तेज था।

vectorize

Numba का उपयोग वेक्टरकृत कार्यों को लिखने के लिए भी किया जा सकता है, जिसमें उपयोगकर्ता को वेक्टर की टिप्पणियों पर स्पष्ट रूप से लूप की आवश्यकता नहीं होती है; एक वेक्टर किए गए फ़ंक्शन को प्रत्येक पंक्ति में स्वचालित रूप से लागू किया जाएगा। प्रत्येक अवलोकन को दोगुना करने के निम्नलिखित खिलौना उदाहरण पर विचार करें:

import numba

def double_every_value_nonumba(x):
    return x*2

@numba.vectorize
def double_every_value_withnumba(x):
    return x*2


# Custom function without numba
In [5]: %timeit df['col1_doubled'] = df.a.apply(double_every_value_nonumba)
1000 loops, best of 3: 797 us per loop

# Standard implementation (faster than a custom function)
In [6]: %timeit df['col1_doubled'] = df.a*2
1000 loops, best of 3: 233 us per loop

# Custom function with numba
In [7]: %timeit df['col1_doubled'] = double_every_value_withnumba(df.a.values)
1000 loops, best of 3: 145 us per loop

चेतावनियां

ध्यान दें

Numba किसी भी फ़ंक्शन को निष्पादित करेगा, लेकिन केवल कुछ वर्गों के कार्यों को गति दे सकता है।

नुम्बा कार्यों में तेजी लाने के लिए सबसे अच्छा है जो संख्यात्मक कार्यों को न्यूपे सरणियों पर लागू करते हैं। जब एक फ़ंक्शन पारित किया गया जो केवल संचालन का उपयोग करता है यह जानता है कि कैसे तेजी लाने के लिए, यह nopython मोड में निष्पादित होगा।

यदि Numba को एक फ़ंक्शन पास किया जाता है, जिसमें कुछ ऐसा शामिल होता है जो यह नहीं जानता कि कैसे काम करना है - एक श्रेणी जिसमें वर्तमान में सेट, सूची, शब्दकोश, या स्ट्रिंग फ़ंक्शन शामिल हैं - यह object mode वापस आ जाएगा। object mode , Numba निष्पादित करेगा लेकिन आपका कोड महत्वपूर्ण रूप से गति नहीं देगा। यदि आप पसंद करेंगे कि नुम्बा एक त्रुटि को फेंक दे अगर वह एक फ़ंक्शन को आपके कोड को गति देने वाले तरीके से संकलित नहीं कर सकता है, तो nopython=True तर्क nopython=True (जैसे @numba.jit(nopython=True) )। समस्या निवारण मोड पर अधिक जानकारी के लिए, Numba समस्या निवारण पृष्ठ देखें

Numba डॉक्स में और पढ़ें।

eval() माध्यम से अभिव्यक्ति का मूल्यांकन eval()

शीर्ष-स्तरीय फ़ंक्शन pandas.eval() Series और DataFrame ऑब्जेक्ट्स के अभिव्यक्ति मूल्यांकन को लागू DataFrame है।

ध्यान दें

numexpr pandas.eval() का उपयोग करने से लाभ के लिए आपको numexpr इंस्टॉल numexpr । अधिक विवरण के लिए अनुशंसित निर्भरता अनुभाग देखें।

सादे पायथन के बजाय अभिव्यक्ति मूल्यांकन के लिए pandas.eval() का उपयोग करने का बिंदु दो गुना है: 1) बड़े DataFrame ऑब्जेक्ट का अधिक कुशलता से मूल्यांकन किया जाता है और 2) बड़े अंकगणितीय और बूलियन अभिव्यक्तियों का मूल्यांकन एक ही बार में अंतर्निहित इंजन (डिफ़ॉल्ट रूप से) द्वारा किया जाता है मूल्यांकन के लिए उपयोग किया जाता है)।

ध्यान दें

आपको सरल अभिव्यक्ति के लिए या छोटे डेटाफ्रैम में शामिल अभिव्यक्तियों के लिए pandas.eval() उपयोग नहीं करना चाहिए। वास्तव में, pandas.eval() प्लेन ol 'पायथन की तुलना में छोटी अभिव्यक्तियों / वस्तुओं के लिए परिमाण धीमे के कई आदेश हैं। अंगूठे का एक अच्छा नियम केवल pandas.eval() उपयोग करना है जब आपके पास 10,000 से अधिक पंक्तियों के साथ DataFrame हो।

pandas.eval() केवल पंडों में उपलब्ध कुछ एक्सटेंशन के अलावा इंजन द्वारा समर्थित सभी अंकगणितीय अभिव्यक्तियों का समर्थन करता है।

ध्यान दें

बड़ा फ्रेम और अभिव्यक्ति जितना अधिक स्पीडअप आप pandas.eval() का उपयोग करके देखेंगे।

सिंटेक्स का समर्थन किया

ये ऑपरेशन pandas.eval() द्वारा समर्थित हैं:

  • बायीं पाली ( << ) और दाहिनी पाली ( >> ) संचालकों को छोड़कर अंकगणित संचालन, जैसे, df + 2 * pi / s ** 4 % 42 - the_golden_ratio
  • तुलनात्मक संचालन, जंजीर तुलना सहित, उदाहरण के लिए, 2 < df < df2
  • बूलियन ऑपरेशन, जैसे, df < df2 and df3 < df4 or not df_bool
  • list और tuple शाब्दिक, उदाहरण के लिए, [1, 2] या (1, 2)
  • विशेषता का उपयोग, जैसे, df.a
  • सदस्यता के भाव, उदाहरण के लिए, df[0]
  • सरल चर मूल्यांकन, उदाहरण के लिए, pd.eval('df') (यह बहुत उपयोगी नहीं है)
  • गणित के कार्य: sin , cos , exp , log , expm1 , log expm1 , log1p , arccosh , arcsinh , arctanh , arccosh , arcsinh , arctanh , arcsinh , arctanh , arcsinh , arctanh और arctan2

इस पायथन सिंटैक्स की अनुमति नहीं है :

  • भाव
    • फ़ंक्शन गणित कार्यों के अलावा अन्य कॉल करता है।
    • is / संचालन is not है
    • if भाव
    • lambda भाव
    • list / set / dict समझ
    • शाब्दिक dict और set भाव
    • yield भाव
    • जनक भाव
    • बूलियन अभिव्यक्तियों में केवल स्केलर मान शामिल हैं
  • बयान
    • न तो simple और न ही compound बयानों की अनुमति है। इसमें शामिल हैं, जैसे, while , और if

eval() उदाहरण हैं

pandas.eval() बड़े सरणियों वाले भावों के साथ अच्छी तरह से काम करता है।

पहले चलो कुछ सभ्य आकार के सरणियों के साथ खेलने के लिए:

In [13]: nrows, ncols = 20000, 100

In [14]: df1, df2, df3, df4 = [pd.DataFrame(np.random.randn(nrows, ncols)) for _ in range(4)]

अब आइए उनकी तुलना सादे ओल 'पाइथन बनाम pandas.eval() करें।

In [15]: %timeit df1 + df2 + df3 + df4
20.8 ms +- 4.36 ms per loop (mean +- std. dev. of 7 runs, 10 loops each)
In [16]: %timeit pd.eval('df1 + df2 + df3 + df4')
7.85 ms +- 473 us per loop (mean +- std. dev. of 7 runs, 100 loops each)

अब एक ही काम करते हैं लेकिन तुलना के साथ:

In [17]: %timeit (df1 > 0) & (df2 > 0) & (df3 > 0) & (df4 > 0)
31.6 ms +- 830 us per loop (mean +- std. dev. of 7 runs, 10 loops each)
In [18]: %timeit pd.eval('(df1 > 0) & (df2 > 0) & (df3 > 0) & (df4 > 0)')
14.2 ms +- 775 us per loop (mean +- std. dev. of 7 runs, 100 loops each)

pandas.eval() अनलॉग्ड पांडा ऑब्जेक्ट्स के साथ भी काम करता है:

In [19]: s = pd.Series(np.random.randn(50))

In [20]: %timeit df1 + df2 + df3 + df4 + s
30.3 ms +- 3.13 ms per loop (mean +- std. dev. of 7 runs, 10 loops each)
In [21]: %timeit pd.eval('df1 + df2 + df3 + df4 + s')
10 ms +- 1.12 ms per loop (mean +- std. dev. of 7 runs, 100 loops each)

ध्यान दें

जैसे संचालन

1 and 2  # would parse to 1 & 2, but should evaluate to 2
3 or 4  # would parse to 3 | 4, but should evaluate to 3
~1  # this is okay, but slower when using eval

अजगर में प्रदर्शन किया जाना चाहिए। यदि आप किसी ऐसे बूलियन / बिटवाइस ऑपरेशन को करने की कोशिश करते हैं, जो स्केलर np.bool_ साथ होता है, जो टाइप bool या np.bool_ । फिर, आपको सादे पायथन में इस प्रकार के ऑपरेशन करने चाहिए।

DataFrame.eval विधि

शीर्ष स्तर pandas.eval() फ़ंक्शन के अतिरिक्त आप किसी DataFrame के "संदर्भ" में एक अभिव्यक्ति का मूल्यांकन भी कर सकते हैं।

In [22]: df = pd.DataFrame(np.random.randn(5, 2), columns=['a', 'b'])

In [23]: df.eval('a + b')
Out[23]: 
0   -0.246747
1    0.867786
2   -1.626063
3   -1.134978
4   -1.027798
dtype: float64

कोई भी व्यंजक जो एक मान्य pandas.eval() अभिव्यक्ति है, एक मान्य DataFrame.eval() अभिव्यक्ति है, अतिरिक्त लाभ के साथ जिसे आपको DataFrame के नाम को स्तंभ में उपसर्ग करने की आवश्यकता नहीं है (दिलचस्पी) मूल्यांकन में।

इसके अलावा, आप एक अभिव्यक्ति के भीतर कॉलम का असाइनमेंट कर सकते हैं। यह सूत्र मूल्यांकन की अनुमति देता है। असाइनमेंट लक्ष्य एक नया कॉलम नाम या मौजूदा कॉलम नाम हो सकता है, और यह एक मान्य पायथन पहचानकर्ता होना चाहिए।

संस्करण में नया 0.18.0।

inplace कीवर्ड यह निर्धारित करता है कि यह असाइनमेंट मूल DataFrame पर किया जाएगा या नए कॉलम के साथ एक प्रति वापस करेगा।

चेतावनी

पीछे की संगतता के लिए, यदि True निर्दिष्ट नहीं है, तो यह inplace लिए है। यह पंडों के भविष्य के संस्करण में बदल जाएगा - यदि आपका कोड एक असेसमेंट असाइनमेंट पर निर्भर करता है, तो आपको स्पष्ट रूप से inplace=True सेट करने के लिए अपडेट करना चाहिए।

In [24]: df = pd.DataFrame(dict(a=range(5), b=range(5, 10)))

In [25]: df.eval('c = a + b', inplace=True)

In [26]: df.eval('d = a + b + c', inplace=True)

In [27]: df.eval('a = 1', inplace=True)

In [28]: df
Out[28]: 
   a  b   c   d
0  1  5   5  10
1  1  6   7  14
2  1  7   9  18
3  1  8  11  22
4  1  9  13  26

जब False को False सेट किया जाता है, तो नए या संशोधित स्तंभों के साथ DataFrame की एक प्रति लौटा दी जाती है और मूल फ़्रेम अपरिवर्तित होता है।

In [29]: df
Out[29]: 
   a  b   c   d
0  1  5   5  10
1  1  6   7  14
2  1  7   9  18
3  1  8  11  22
4  1  9  13  26

In [30]: df.eval('e = a - c', inplace=False)