Skip to content

Commit 94dd38d

Browse files
committed
PERF: delay numexpr
1 parent 99b602d commit 94dd38d

File tree

11 files changed

+54
-38
lines changed

11 files changed

+54
-38
lines changed

pandas/core/computation/__init__.py

-23
Original file line numberDiff line numberDiff line change
@@ -1,23 +0,0 @@
1-
2-
import warnings
3-
from distutils.version import LooseVersion
4-
5-
_NUMEXPR_INSTALLED = False
6-
_MIN_NUMEXPR_VERSION = "2.4.6"
7-
8-
try:
9-
import numexpr as ne
10-
ver = ne.__version__
11-
_NUMEXPR_INSTALLED = ver >= LooseVersion(_MIN_NUMEXPR_VERSION)
12-
13-
if not _NUMEXPR_INSTALLED:
14-
warnings.warn(
15-
"The installed version of numexpr {ver} is not supported "
16-
"in pandas and will be not be used\nThe minimum supported "
17-
"version is {min_ver}\n".format(
18-
ver=ver, min_ver=_MIN_NUMEXPR_VERSION), UserWarning)
19-
20-
except ImportError: # pragma: no cover
21-
pass
22-
23-
__all__ = ['_NUMEXPR_INSTALLED']

pandas/core/computation/check.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import warnings
2+
from distutils.version import LooseVersion
3+
4+
_NUMEXPR_INSTALLED = False
5+
_MIN_NUMEXPR_VERSION = "2.4.6"
6+
7+
try:
8+
import numexpr as ne
9+
ver = ne.__version__
10+
_NUMEXPR_INSTALLED = ver >= LooseVersion(_MIN_NUMEXPR_VERSION)
11+
12+
if not _NUMEXPR_INSTALLED:
13+
warnings.warn(
14+
"The installed version of numexpr {ver} is not supported "
15+
"in pandas and will be not be used\nThe minimum supported "
16+
"version is {min_ver}\n".format(
17+
ver=ver, min_ver=_MIN_NUMEXPR_VERSION), UserWarning)
18+
19+
except ImportError: # pragma: no cover
20+
pass
21+
22+
__all__ = ['_NUMEXPR_INSTALLED']

pandas/core/computation/eval.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
import tokenize
77
from pandas.io.formats.printing import pprint_thing
8-
from pandas.core.computation import _NUMEXPR_INSTALLED
9-
from pandas.core.computation.expr import Expr, _parsers, tokenize_string
108
from pandas.core.computation.scope import _ensure_scope
119
from pandas.compat import string_types
1210
from pandas.core.computation.engines import _engines
@@ -32,6 +30,7 @@ def _check_engine(engine):
3230
string engine
3331
3432
"""
33+
from pandas.core.computation.check import _NUMEXPR_INSTALLED
3534

3635
if engine is None:
3736
if _NUMEXPR_INSTALLED:
@@ -69,6 +68,8 @@ def _check_parser(parser):
6968
KeyError
7069
* If an invalid parser is passed
7170
"""
71+
from pandas.core.computation.expr import _parsers
72+
7273
if parser not in _parsers:
7374
raise KeyError('Invalid parser {parser!r} passed, valid parsers are'
7475
' {valid}'.format(parser=parser, valid=_parsers.keys()))
@@ -129,6 +130,8 @@ def _convert_expression(expr):
129130

130131

131132
def _check_for_locals(expr, stack_level, parser):
133+
from pandas.core.computation.expr import tokenize_string
134+
132135
at_top_of_stack = stack_level == 0
133136
not_pandas_parser = parser != 'pandas'
134137

@@ -252,6 +255,7 @@ def eval(expr, parser='pandas', engine=None, truediv=True,
252255
pandas.DataFrame.query
253256
pandas.DataFrame.eval
254257
"""
258+
from pandas.core.computation.expr import Expr
255259

256260
inplace = validate_bool_kwarg(inplace, "inplace")
257261

pandas/core/computation/expressions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import warnings
1010
import numpy as np
1111
from pandas.core.common import _values_from_object
12-
from pandas.core.computation import _NUMEXPR_INSTALLED
12+
from pandas.core.computation.check import _NUMEXPR_INSTALLED
1313
from pandas.core.config import get_option
1414

1515
if _NUMEXPR_INSTALLED:

pandas/core/frame.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@
7676
create_block_manager_from_blocks)
7777
from pandas.core.series import Series
7878
from pandas.core.categorical import Categorical
79-
import pandas.core.computation.expressions as expressions
8079
import pandas.core.algorithms as algorithms
81-
from pandas.core.computation.eval import eval as _eval
8280
from pandas.compat import (range, map, zip, lrange, lmap, lzip, StringIO, u,
8381
OrderedDict, raise_with_traceback)
8482
from pandas import compat
@@ -2296,6 +2294,8 @@ def eval(self, expr, inplace=False, **kwargs):
22962294
>>> df.eval('a + b')
22972295
>>> df.eval('c = a + b')
22982296
"""
2297+
from pandas.core.computation.eval import eval as _eval
2298+
22992299
inplace = validate_bool_kwarg(inplace, 'inplace')
23002300
resolvers = kwargs.pop('resolvers', None)
23012301
kwargs['level'] = kwargs.pop('level', 0) + 1
@@ -3845,6 +3845,7 @@ def _combine_const(self, other, func, raise_on_error=True, try_cast=True):
38453845

38463846
def _compare_frame_evaluate(self, other, func, str_rep, try_cast=True):
38473847

3848+
import pandas.core.computation.expressions as expressions
38483849
# unique
38493850
if self.columns.is_unique:
38503851

@@ -3997,6 +3998,7 @@ def combine_first(self, other):
39973998
-------
39983999
combined : DataFrame
39994000
"""
4001+
import pandas.core.computation.expressions as expressions
40004002

40014003
def combiner(x, y, needs_i8_conversion=False):
40024004
x_values = x.values if hasattr(x, 'values') else x
@@ -4032,6 +4034,7 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
40324034
If True, will raise an error if the DataFrame and other both
40334035
contain data in the same place.
40344036
"""
4037+
import pandas.core.computation.expressions as expressions
40354038
# TODO: Support other joins
40364039
if join != 'left': # pragma: no cover
40374040
raise NotImplementedError("Only left join is supported")

pandas/core/internals.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
from pandas._libs.tslib import Timedelta
6767
from pandas._libs.lib import BlockPlacement
6868

69-
import pandas.core.computation.expressions as expressions
7069
from pandas.util._decorators import cache_readonly
7170
from pandas.util._validators import validate_bool_kwarg
7271
from pandas import compat
@@ -1395,6 +1394,8 @@ def where(self, other, cond, align=True, raise_on_error=True,
13951394
-------
13961395
a new block(s), the result of the func
13971396
"""
1397+
import pandas.core.computation.expressions as expressions
1398+
13981399
values = self.values
13991400
orig_other = other
14001401
if transpose:

pandas/core/ops.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
from pandas import compat
1818
from pandas.util._decorators import Appender
19-
import pandas.core.computation.expressions as expressions
2019

2120
from pandas.compat import bind_method
2221
import pandas.core.missing as missing
@@ -668,8 +667,9 @@ def _arith_method_SERIES(op, name, str_rep, fill_zeros=None, default_axis=None,
668667
Wrapper function for Series arithmetic operations, to avoid
669668
code duplication.
670669
"""
671-
672670
def na_op(x, y):
671+
import pandas.core.computation.expressions as expressions
672+
673673
try:
674674
result = expressions.evaluate(op, str_rep, x, y,
675675
raise_on_error=True, **eval_kwargs)
@@ -1193,6 +1193,8 @@ def to_series(right):
11931193
def _arith_method_FRAME(op, name, str_rep=None, default_axis='columns',
11941194
fill_zeros=None, **eval_kwargs):
11951195
def na_op(x, y):
1196+
import pandas.core.computation.expressions as expressions
1197+
11961198
try:
11971199
result = expressions.evaluate(op, str_rep, x, y,
11981200
raise_on_error=True, **eval_kwargs)
@@ -1349,6 +1351,8 @@ def _arith_method_PANEL(op, name, str_rep=None, fill_zeros=None,
13491351
# copied from Series na_op above, but without unnecessary branch for
13501352
# non-scalar
13511353
def na_op(x, y):
1354+
import pandas.core.computation.expressions as expressions
1355+
13521356
try:
13531357
result = expressions.evaluate(op, str_rep, x, y,
13541358
raise_on_error=True, **eval_kwargs)
@@ -1378,6 +1382,8 @@ def f(self, other):
13781382

13791383
def _comp_method_PANEL(op, name, str_rep=None, masker=False):
13801384
def na_op(x, y):
1385+
import pandas.core.computation.expressions as expressions
1386+
13811387
try:
13821388
result = expressions.evaluate(op, str_rep, x, y,
13831389
raise_on_error=True)

pandas/core/panel.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
is_string_like, is_scalar)
1616
from pandas.core.dtypes.missing import notna
1717

18-
import pandas.core.computation.expressions as expressions
1918
import pandas.core.common as com
2019
import pandas.core.ops as ops
2120
import pandas.core.missing as missing
@@ -1500,6 +1499,8 @@ def _add_aggregate_operations(cls, use_numexpr=True):
15001499
def _panel_arith_method(op, name, str_rep=None, default_axis=None,
15011500
fill_zeros=None, **eval_kwargs):
15021501
def na_op(x, y):
1502+
import pandas.core.computation.expressions as expressions
1503+
15031504
try:
15041505
result = expressions.evaluate(op, str_rep, x, y,
15051506
raise_on_error=True,

pandas/tests/computation/test_compat.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55

66
from pandas.core.computation.engines import _engines
77
import pandas.core.computation.expr as expr
8-
from pandas.core.computation import _MIN_NUMEXPR_VERSION
8+
from pandas.core.computation.check import _MIN_NUMEXPR_VERSION
99

1010

1111
def test_compat():
1212
# test we have compat with our version of nu
1313

14-
from pandas.core.computation import _NUMEXPR_INSTALLED
14+
from pandas.core.computation.check import _NUMEXPR_INSTALLED
1515
try:
1616
import numexpr as ne
1717
ver = ne.__version__

pandas/tests/frame/test_query_eval.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
makeCustomDataframe as mkdf)
1818

1919
import pandas.util.testing as tm
20-
from pandas.core.computation import _NUMEXPR_INSTALLED
20+
from pandas.core.computation.check import _NUMEXPR_INSTALLED
2121

2222
from pandas.tests.frame.common import TestData
2323

pandas/util/testing.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
StringIO, PY3
4242
)
4343

44-
from pandas.core.computation import expressions as expr
45-
4644
from pandas import (bdate_range, CategoricalIndex, Categorical, IntervalIndex,
4745
DatetimeIndex, TimedeltaIndex, PeriodIndex, RangeIndex,
4846
Index, MultiIndex,
@@ -2660,7 +2658,11 @@ def __exit__(self, exc_type, exc_value, traceback):
26602658

26612659

26622660
@contextmanager
2663-
def use_numexpr(use, min_elements=expr._MIN_ELEMENTS):
2661+
def use_numexpr(use, min_elements=None):
2662+
from pandas.core.computation import expressions as expr
2663+
if min_elements is None:
2664+
min_elements = expr._MIN_ELEMENTS
2665+
26642666
olduse = expr._USE_NUMEXPR
26652667
oldmin = expr._MIN_ELEMENTS
26662668
expr.set_use_numexpr(use)

0 commit comments

Comments
 (0)