From f3b0fba820cd7e3ea1b294694ebf2d0c9c9e62aa Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 12 Nov 2020 15:55:43 -0800 Subject: [PATCH 1/2] REF: avoid try/except in Block.where --- pandas/core/internals/blocks.py | 39 ++++++++++++++------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index ed77a210b6913..c63ed96ed1a0a 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -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): + # 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) @@ -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: From 125a740f4e285b2b676be3d3ac725b3262d80e0e Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 12 Nov 2020 21:06:44 -0800 Subject: [PATCH 2/2] comment --- pandas/core/internals/blocks.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index fa8051598eddb..3d5ed1bcb5759 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1447,10 +1447,14 @@ def where( else: # see if we can operate on the entire block, or need item-by-item # or if we are a single block (ndim == 1) - if self.is_bool and lib.is_float(other) and np.isnan(other): + if ( + (self.is_integer or self.is_bool) + and lib.is_float(other) + and np.isnan(other) + ): # GH#3733 special case to avoid object-dtype casting - # and go through numexpr path instead. - + # and go through numexpr path instead. + # In integer case, np.where will cast to floats pass elif not self._can_hold_element(other): # we cannot coerce, return a compat dtype @@ -1470,7 +1474,7 @@ def where( other = convert_scalar_for_putitemlike(other, values.dtype) # By the time we get here, we should have all Series/Index - # args extracted to ndarray + # args extracted to ndarray result = expressions.where(cond, values, other) if self._can_hold_na or self.ndim == 1: