diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1e5b0a107615e..359d89ce664c3 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -118,6 +118,7 @@ nanops, ) import pandas.core.algorithms as algos +from pandas.core.array_algos.replace import should_use_regex from pandas.core.arrays import ExtensionArray from pandas.core.base import PandasObject import pandas.core.common as com @@ -6688,9 +6689,17 @@ def replace( return self._replace_columnwise(mapping, inplace, regex) elif not is_list_like(value): # NA -> 0 - new_data = self._mgr.replace( - to_replace=to_replace, value=value, inplace=inplace, regex=regex - ) + regex = should_use_regex(regex, to_replace) + if regex: + new_data = self._mgr.replace_regex( + to_replace=to_replace, + value=value, + inplace=inplace, + ) + else: + new_data = self._mgr.replace( + to_replace=to_replace, value=value, inplace=inplace + ) else: raise TypeError( f'Invalid "to_replace" type: {repr(type(to_replace).__name__)}' diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 93a9e8fbcb1ad..09f16a2ddab67 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -413,11 +413,17 @@ def _convert(arr): return self.apply(_convert) - def replace(self: T, value, **kwargs) -> T: + def replace_regex(self: T, **kwargs) -> T: + return self.apply_with_block("_replace_regex", **kwargs) + + def replace(self: T, to_replace, value, inplace: bool) -> T: + inplace = validate_bool_kwarg(inplace, "inplace") assert np.ndim(value) == 0, value # TODO "replace" is right now implemented on the blocks, we should move # it to general array algos so it can be reused here - return self.apply_with_block("replace", value=value, **kwargs) + return self.apply_with_block( + "replace", value=value, to_replace=to_replace, inplace=inplace + ) def replace_list( self: T, diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 7056a34c73008..da2ff58ea3d0d 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -640,14 +640,11 @@ def replace( to_replace, value, inplace: bool = False, - regex: bool = False, ) -> list[Block]: """ replace the to_replace value with value, possible to create new - blocks here this is just a call to putmask. regex is not used here. - It is used in ObjectBlocks. It is here for API compatibility. + blocks here this is just a call to putmask. """ - inplace = validate_bool_kwarg(inplace, "inplace") # Note: the checks we do in NDFrame.replace ensure we never get # here with listlike to_replace or value, as those cases @@ -661,11 +658,6 @@ def replace( blk.values._replace(to_replace=to_replace, value=value, inplace=True) return [blk] - regex = should_use_regex(regex, to_replace) - - if regex: - return self._replace_regex(to_replace, value, inplace=inplace) - if not self._can_hold_element(to_replace): # We cannot hold `to_replace`, so we know immediately that # replacing it is a no-op. @@ -691,13 +683,12 @@ def replace( to_replace=to_replace, value=value, inplace=True, - regex=regex, ) else: # split so that we only upcast where necessary return self.split_and_operate( - type(self).replace, to_replace, value, inplace=True, regex=regex + type(self).replace, to_replace, value, inplace=True ) @final @@ -756,10 +747,14 @@ def replace_list( values = self.values # TODO: dont special-case Categorical - if isinstance(values, Categorical) and len(algos.unique(dest_list)) == 1: + if ( + isinstance(values, Categorical) + and len(algos.unique(dest_list)) == 1 + and not regex + ): # We likely got here by tiling value inside NDFrame.replace, # so un-tile here - return self.replace(src_list, dest_list[0], inplace, regex) + return self.replace(src_list, dest_list[0], inplace) # Exclude anything that we know we won't contain pairs = [ @@ -866,7 +861,7 @@ def _replace_coerce( convert=False, mask=mask, ) - return self.replace(to_replace, value, inplace=inplace, regex=False) + return self.replace(to_replace, value, inplace=inplace) return [self] # --------------------------------------------------------------------- diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index cb18c6cccbc60..5ebc0292f24b4 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -432,12 +432,18 @@ def convert( timedelta=timedelta, ) - def replace(self: T, to_replace, value, inplace: bool, regex: bool) -> T: - assert np.ndim(value) == 0, value + def replace(self: T, to_replace, value, inplace: bool) -> T: + inplace = validate_bool_kwarg(inplace, "inplace") + # NDFrame.replace ensures the not-is_list_likes here + assert not is_list_like(to_replace) + assert not is_list_like(value) return self.apply( - "replace", to_replace=to_replace, value=value, inplace=inplace, regex=regex + "replace", to_replace=to_replace, value=value, inplace=inplace ) + def replace_regex(self, **kwargs): + return self.apply("_replace_regex", **kwargs) + def replace_list( self: T, src_list: list[Any],