Skip to content

Commit 0dec048

Browse files
committed
BUG: Bug in expressions evaluation with reversed ops, showing in series-dataframe ops (GH7198)
1 parent 415cba2 commit 0dec048

File tree

5 files changed

+58
-8
lines changed

5 files changed

+58
-8
lines changed

doc/source/release.rst

+1
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ Bug Fixes
534534
(:issue:`7178`)
535535
- Bug in recognizing out-of-bounds positional list indexers with ``iloc`` and a multi-axis tuple indexer (:issue:`7189`)
536536
- Bug in setitem with a single value, multi-index and integer indices (:issue:`7190`)
537+
- Bug in expressions evaluation with reversed ops, showing in series-dataframe ops (:issue:`7198`, :issue:`7192`)
537538

538539
pandas 0.13.1
539540
-------------

pandas/computation/expressions.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,18 @@ def _can_use_numexpr(op, op_str, a, b, dtype_check):
8989
return False
9090

9191

92-
def _evaluate_numexpr(op, op_str, a, b, raise_on_error=False, truediv=True,
92+
def _evaluate_numexpr(op, op_str, a, b, raise_on_error=False, truediv=True, reversed=False,
9393
**eval_kwargs):
9494
result = None
9595

9696
if _can_use_numexpr(op, op_str, a, b, 'evaluate'):
9797
try:
98+
99+
# we were originally called by a reversed op
100+
# method
101+
if reversed:
102+
a,b = b,a
103+
98104
a_value = getattr(a, "values", a)
99105
b_value = getattr(b, "values", b)
100106
result = ne.evaluate('a_value %s b_value' % op_str,

pandas/core/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2256,7 +2256,7 @@ def set_index(self, keys, drop=True, append=False, inplace=False,
22562256
names.append(col.name)
22572257
elif isinstance(col, Index):
22582258
level = col
2259-
names.append(col.name)
2259+
names.append(col.name)
22602260
elif isinstance(col, (list, np.ndarray)):
22612261
level = col
22622262
names.append(None)

pandas/core/ops.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,21 @@ def names(x):
6868
# not entirely sure why this is necessary, but previously was included
6969
# so it's here to maintain compatibility
7070
rmul=arith_method(operator.mul, names('rmul'), op('*'),
71-
default_axis=default_axis),
71+
default_axis=default_axis, reversed=True),
7272
rsub=arith_method(lambda x, y: y - x, names('rsub'), op('-'),
73-
default_axis=default_axis),
73+
default_axis=default_axis, reversed=True),
7474
rtruediv=arith_method(lambda x, y: operator.truediv(y, x),
7575
names('rtruediv'), op('/'), truediv=True,
76-
fill_zeros=np.inf, default_axis=default_axis),
76+
fill_zeros=np.inf, default_axis=default_axis,
77+
reversed=True),
7778
rfloordiv=arith_method(lambda x, y: operator.floordiv(y, x),
7879
names('rfloordiv'), op('//'),
79-
default_axis=default_axis, fill_zeros=np.inf),
80+
default_axis=default_axis, fill_zeros=np.inf,
81+
reversed=True),
8082
rpow=arith_method(lambda x, y: y ** x, names('rpow'), op('**'),
81-
default_axis=default_axis),
83+
default_axis=default_axis, reversed=True),
8284
rmod=arith_method(lambda x, y: y % x, names('rmod'), op('%'),
83-
default_axis=default_axis),
85+
default_axis=default_axis, reversed=True),
8486
)
8587
new_methods['div'] = new_methods['truediv']
8688
new_methods['rdiv'] = new_methods['rtruediv']

pandas/tests/test_frame.py

+41
Original file line numberDiff line numberDiff line change
@@ -8351,6 +8351,47 @@ def test_combine_multiple_frames_dtypes(self):
83518351
expected = Series(dict( float64 = 2, float32 = 2 ))
83528352
assert_series_equal(results,expected)
83538353

8354+
def test_ops(self):
8355+
8356+
# tst ops and reversed ops in evaluation
8357+
# GH7198
8358+
8359+
# smaller hits python, larger hits numexpr
8360+
for n in [ 4, 4000 ]:
8361+
8362+
df = DataFrame(1,index=range(n),columns=list('abcd'))
8363+
df.iloc[0] = 2
8364+
m = df.mean()
8365+
8366+
for op_str, op, rop in [('+','__add__','__radd__'),
8367+
('-','__sub__','__rsub__'),
8368+
('*','__mul__','__rmul__'),
8369+
('/','__truediv__','__rtruediv__')]:
8370+
8371+
base = DataFrame(np.tile(m.values,n).reshape(n,-1),columns=list('abcd'))
8372+
expected = eval("base{op}df".format(op=op_str))
8373+
8374+
# ops as strings
8375+
result = eval("m{op}df".format(op=op_str))
8376+
assert_frame_equal(result,expected)
8377+
8378+
# these are commutative
8379+
if op in ['+','*']:
8380+
result = getattr(df,op)(m)
8381+
assert_frame_equal(result,expected)
8382+
8383+
# these are not
8384+
elif op in ['-','/']:
8385+
result = getattr(df,rop)(m)
8386+
assert_frame_equal(result,expected)
8387+
8388+
# GH7192
8389+
df = DataFrame(dict(A=np.random.randn(25000)))
8390+
df.iloc[0:5] = np.nan
8391+
expected = (1-np.isnan(df.iloc[0:25]))
8392+
result = (1-np.isnan(df)).iloc[0:25]
8393+
assert_frame_equal(result,expected)
8394+
83548395
def test_truncate(self):
83558396
offset = datetools.bday
83568397

0 commit comments

Comments
 (0)