diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index 1c2e55c3e37df..db45f140c268e 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -1673,7 +1673,10 @@ def union_with_duplicates( def map_array( - arr: ArrayLike, mapper, na_action: Literal["ignore"] | None = None + arr: ArrayLike, + mapper, + na_action: Literal["ignore"] | None = None, + convert: bool = True, ) -> np.ndarray | ExtensionArray | Index: """ Map values using an input mapping or function. @@ -1685,6 +1688,9 @@ def map_array( na_action : {None, 'ignore'}, default None If 'ignore', propagate NA values, without passing them to the mapping correspondence. + convert : bool, default True + Try to find better dtype for elementwise function results. If + False, leave as dtype=object. Returns ------- @@ -1739,6 +1745,8 @@ def map_array( # we must convert to python types values = arr.astype(object, copy=False) if na_action is None: - return lib.map_infer(values, mapper) + return lib.map_infer(values, mapper, convert=convert) else: - return lib.map_infer_mask(values, mapper, isna(values).view(np.uint8)) + return lib.map_infer_mask( + values, mapper, mask=isna(values).view(np.uint8), convert=convert + ) diff --git a/pandas/core/apply.py b/pandas/core/apply.py index f23b05a5c41b8..65fe9144618ee 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -24,7 +24,6 @@ from pandas._config import option_context -from pandas._libs import lib from pandas._typing import ( AggFuncType, AggFuncTypeBase, @@ -1063,20 +1062,12 @@ def apply_standard(self) -> DataFrame | Series: f = cast(Callable, self.f) obj = self.obj - with np.errstate(all="ignore"): - if isinstance(f, np.ufunc): + if isinstance(f, np.ufunc): + with np.errstate(all="ignore"): return f(obj) - # row-wise access - if is_extension_array_dtype(obj.dtype): - mapped = obj._values.map(f) - else: - values = obj.astype(object)._values - mapped = lib.map_infer( - values, - f, - convert=self.convert_dtype, - ) + # row-wise access + mapped = obj._map_values(mapper=f, convert=self.convert_dtype) if len(mapped) and isinstance(mapped[0], ABCSeries): # GH#43986 Need to do list(mapped) in order to get treated as nested diff --git a/pandas/core/base.py b/pandas/core/base.py index 2177b8f3d58a3..dc37550ced387 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -865,7 +865,7 @@ def _reduce( return func(skipna=skipna, **kwds) @final - def _map_values(self, mapper, na_action=None): + def _map_values(self, mapper, na_action=None, convert: bool = True): """ An internal function that maps values using the input correspondence (which can be a dict, Series, or function). @@ -877,6 +877,10 @@ def _map_values(self, mapper, na_action=None): na_action : {None, 'ignore'} If 'ignore', propagate NA values, without passing them to the mapping function + convert : bool, default True + Try to find better dtype for elementwise function results. If + False, leave as dtype=object. Note that the dtype is always + preserved for some extension array dtypes, such as Categorical. Returns ------- @@ -894,7 +898,7 @@ def _map_values(self, mapper, na_action=None): # "Union[IndexOpsMixin, ExtensionArray, ndarray[Any, Any]]"; # expected "Union[ExtensionArray, ndarray[Any, Any]]" return algorithms.map_array( - arr, mapper, na_action=na_action # type: ignore[arg-type] + arr, mapper, na_action=na_action, convert=convert # type: ignore[arg-type] ) @final