Skip to content

REF: avoid try/except in Block.where #37802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 13, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,34 +1452,17 @@ def where(
if not hasattr(cond, "shape"):
raise ValueError("where must have a condition that is ndarray like")

def where_func(cond, values, other):

if not (
(self.is_integer or self.is_bool)
and lib.is_float(other)
and np.isnan(other)
):
# np.where will cast integer array to floats in this case
if not self._can_hold_element(other):
raise TypeError
if lib.is_scalar(other) and isinstance(values, np.ndarray):
# convert datetime to datetime64, timedelta to timedelta64
other = convert_scalar_for_putitemlike(other, values.dtype)

# By the time we get here, we should have all Series/Index
# args extracted to ndarray
fastres = expressions.where(cond, values, other)
return fastres

if cond.ravel("K").all():
result = values
else:
# see if we can operate on the entire block, or need item-by-item
# or if we are a single block (ndim == 1)
try:
result = where_func(cond, values, other)
except TypeError:
if self.is_bool and lib.is_float(other) and np.isnan(other):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prob can lif this to one higher level (and the elif below)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think that would take some gymnastics to avoid having the L1455-1456 cases fall through to the expressions.where call

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure can be a followup

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this include self.integer (e.g. the same case you have on L1474)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changing the self.is_bool to (self.is_integer or self.is_bool) here doesn't break any tests, and i guess going through expressions may be more performant (though im not wild about the casting being not-super-obvious). will update.

# GH#3733 special case to avoid object-dtype casting
# and go through numexpr path instead.

pass
elif not self._can_hold_element(other):
# we cannot coerce, return a compat dtype
# we are explicitly ignoring errors
block = self.coerce_to_target_dtype(other)
Expand All @@ -1488,6 +1471,18 @@ def where_func(cond, values, other):
)
return self._maybe_downcast(blocks, "infer")

if not (
(self.is_integer or self.is_bool)
and lib.is_float(other)
and np.isnan(other)
):
# convert datetime to datetime64, timedelta to timedelta64
other = convert_scalar_for_putitemlike(other, values.dtype)

# By the time we get here, we should have all Series/Index
# args extracted to ndarray
result = expressions.where(cond, values, other)

if self._can_hold_na or self.ndim == 1:

if transpose:
Expand Down