From 9e2848da900950d414901c126ba333818e301448 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 16 Sep 2021 13:21:16 -0700 Subject: [PATCH 1/2] PERF: Block.apply --- pandas/core/internals/blocks.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index bcb4dd284465b..35b5b38cc1741 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -373,8 +373,7 @@ def apply(self, func, **kwargs) -> list[Block]: apply the function to my values; return a block if we are not one """ - with np.errstate(all="ignore"): - result = func(self.values, **kwargs) + result = func(self.values, **kwargs) return self._split_op_result(result) @@ -400,9 +399,9 @@ def reduce(self, func, ignore_failures: bool = False) -> list[Block]: return [nb] @final - def _split_op_result(self, result) -> list[Block]: + def _split_op_result(self, result: ArrayLike) -> list[Block]: # See also: split_and_operate - if is_extension_array_dtype(result) and result.ndim > 1: + if result.ndim > 1 and isinstance(result.dtype, ExtensionDtype): # TODO(EA2D): unnecessary with 2D EAs # if we get a 2D ExtensionArray, we need to split it into 1D pieces nbs = [] @@ -416,9 +415,7 @@ def _split_op_result(self, result) -> list[Block]: nbs.append(block) return nbs - if not isinstance(result, Block): - result = maybe_coerce_values(result) - result = self.make_block(result) + result = self.make_block(result) return [result] @@ -475,7 +472,8 @@ def _split(self) -> list[Block]: for i, ref_loc in enumerate(self._mgr_locs): vals = self.values[slice(i, i + 1)] - nb = self.make_block(vals, BlockPlacement(ref_loc)) + bp = BlockPlacement(ref_loc) + nb = type(self)(vals, placement=bp, ndim=2) new_blocks.append(nb) return new_blocks @@ -648,7 +646,7 @@ def copy(self, deep: bool = True): values = self.values if deep: values = values.copy() - return self.make_block_same_class(values) + return type(self)(values, placement=self._mgr_locs, ndim=self.ndim) # --------------------------------------------------------------------- # Replace @@ -1961,7 +1959,7 @@ def get_block_type(values, dtype: DtypeObj | None = None): return cls -def new_block(values, placement, *, ndim: int, klass=None) -> Block: +def new_block(values, placement, *, ndim: int) -> Block: # caller is responsible for ensuring values is NOT a PandasArray if not isinstance(placement, BlockPlacement): @@ -1969,8 +1967,7 @@ def new_block(values, placement, *, ndim: int, klass=None) -> Block: check_ndim(values, placement, ndim) - if klass is None: - klass = get_block_type(values, values.dtype) + klass = get_block_type(values, values.dtype) values = maybe_coerce_values(values) return klass(values, ndim=ndim, placement=placement) From 24266a209d2ad5056c983faa489c1158735b4437 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 17 Sep 2021 10:58:26 -0700 Subject: [PATCH 2/2] check for warning in test --- pandas/tests/apply/test_str.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pandas/tests/apply/test_str.py b/pandas/tests/apply/test_str.py index 67e8dd520dc3b..6c6b674ef6aab 100644 --- a/pandas/tests/apply/test_str.py +++ b/pandas/tests/apply/test_str.py @@ -72,8 +72,17 @@ def test_apply_np_reducer(float_frame, op, how): @pytest.mark.parametrize("how", ["transform", "apply"]) def test_apply_np_transformer(float_frame, op, how): # GH 39116 - result = getattr(float_frame, how)(op) - expected = getattr(np, op)(float_frame) + + # float_frame will _usually_ have negative values, which will + # trigger the warning here, but let's put one in just to be sure + float_frame.iloc[0, 0] = -1.0 + warn = None + if op in ["log", "sqrt"]: + warn = RuntimeWarning + + with tm.assert_produces_warning(warn): + result = getattr(float_frame, how)(op) + expected = getattr(np, op)(float_frame) tm.assert_frame_equal(result, expected)