Skip to content

Commit 9e64be3

Browse files
committed
Merge branch 'master' of https://github.com/pandas-dev/pandas into ref-blockwise-3
2 parents c632c9f + 9468071 commit 9e64be3

File tree

4 files changed

+36
-14
lines changed

4 files changed

+36
-14
lines changed

doc/source/whatsnew/v1.1.2.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Fixed regressions
2424

2525
Bug fixes
2626
~~~~~~~~~
27-
27+
- Bug in :meth:`DataFrame.eval` with ``object`` dtype column binary operations (:issue:`35794`)
2828
-
2929
-
3030

pandas/core/computation/ops.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,21 @@ def stringify(value):
481481
self.lhs.update(v)
482482

483483
def _disallow_scalar_only_bool_ops(self):
484+
rhs = self.rhs
485+
lhs = self.lhs
486+
487+
# GH#24883 unwrap dtype if necessary to ensure we have a type object
488+
rhs_rt = rhs.return_type
489+
rhs_rt = getattr(rhs_rt, "type", rhs_rt)
490+
lhs_rt = lhs.return_type
491+
lhs_rt = getattr(lhs_rt, "type", lhs_rt)
484492
if (
485-
(self.lhs.is_scalar or self.rhs.is_scalar)
493+
(lhs.is_scalar or rhs.is_scalar)
486494
and self.op in _bool_ops_dict
487495
and (
488496
not (
489-
issubclass(self.rhs.return_type, (bool, np.bool_))
490-
and issubclass(self.lhs.return_type, (bool, np.bool_))
497+
issubclass(rhs_rt, (bool, np.bool_))
498+
and issubclass(lhs_rt, (bool, np.bool_))
491499
)
492500
)
493501
):

pandas/core/window/rolling.py

+17-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from pandas._libs.tslibs import BaseOffset, to_offset
1414
import pandas._libs.window.aggregations as window_aggregations
15-
from pandas._typing import ArrayLike, Axis, FrameOrSeries, Scalar
15+
from pandas._typing import ArrayLike, Axis, FrameOrSeries, Label
1616
from pandas.compat._optional import import_optional_dependency
1717
from pandas.compat.numpy import function as nv
1818
from pandas.util._decorators import Appender, Substitution, cache_readonly, doc
@@ -381,21 +381,31 @@ def _wrap_result(self, result, block=None, obj=None):
381381
return type(obj)(result, index=index, columns=block.columns)
382382
return result
383383

384-
def _wrap_results(self, results, blocks, obj, exclude=None) -> FrameOrSeries:
384+
def _wrap_results(self, results, obj, skipped: List[int]) -> FrameOrSeries:
385385
"""
386386
Wrap the results.
387387
388388
Parameters
389389
----------
390390
results : list of ndarrays
391-
blocks : list of blocks
392391
obj : conformed data (may be resampled)
393-
exclude: list of columns to exclude, default to None
392+
skipped: List[int]
393+
Indices of blocks that are skipped.
394394
"""
395395
from pandas import Series, concat
396396

397+
exclude: List[Label] = []
398+
if obj.ndim == 2:
399+
orig_blocks = list(obj._to_dict_of_blocks(copy=False).values())
400+
for i in skipped:
401+
exclude.extend(orig_blocks[i].columns)
402+
else:
403+
orig_blocks = [obj]
404+
405+
kept_blocks = [blk for i, blk in enumerate(orig_blocks) if i not in skipped]
406+
397407
final = []
398-
for result, block in zip(results, blocks):
408+
for result, block in zip(results, kept_blocks):
399409

400410
result = self._wrap_result(result, block=block, obj=obj)
401411
if result.ndim == 1:
@@ -491,24 +501,21 @@ def _apply_blockwise(
491501

492502
skipped: List[int] = []
493503
results: List[ArrayLike] = []
494-
exclude: List[Scalar] = []
495504
for i, b in enumerate(blocks):
496505
try:
497506
values = self._prep_values(b.values)
498507

499508
except (TypeError, NotImplementedError) as err:
500509
if isinstance(obj, ABCDataFrame):
501510
skipped.append(i)
502-
exclude.extend(b.columns)
503511
continue
504512
else:
505513
raise DataError("No numeric types to aggregate") from err
506514

507515
result = homogeneous_func(values)
508516
results.append(result)
509517

510-
block_list = [blk for i, blk in enumerate(blocks) if i not in skipped]
511-
return self._wrap_results(results, block_list, obj, exclude)
518+
return self._wrap_results(results, obj, skipped)
512519

513520
def _apply(
514521
self,
@@ -1283,7 +1290,7 @@ def count(self):
12831290
).sum()
12841291
results.append(result)
12851292

1286-
return self._wrap_results(results, blocks, obj)
1293+
return self._wrap_results(results, obj, skipped=[])
12871294

12881295
_shared_docs["apply"] = dedent(
12891296
r"""

pandas/tests/frame/test_query_eval.py

+7
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ def test_eval_resolvers_as_list(self):
160160
assert df.eval("a + b", resolvers=[dict1, dict2]) == dict1["a"] + dict2["b"]
161161
assert pd.eval("a + b", resolvers=[dict1, dict2]) == dict1["a"] + dict2["b"]
162162

163+
def test_eval_object_dtype_binop(self):
164+
# GH#24883
165+
df = pd.DataFrame({"a1": ["Y", "N"]})
166+
res = df.eval("c = ((a1 == 'Y') & True)")
167+
expected = pd.DataFrame({"a1": ["Y", "N"], "c": [True, False]})
168+
tm.assert_frame_equal(res, expected)
169+
163170

164171
class TestDataFrameQueryWithMultiIndex:
165172
def test_query_with_named_multiindex(self, parser, engine):

0 commit comments

Comments
 (0)