diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e9996dcf8bc6a..83084f78ccc3b 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -82,6 +82,7 @@ Other enhancements - :meth:`Series.map` can now accept kwargs to pass on to func (:issue:`59814`) - :meth:`Series.map` now accepts an ``engine`` parameter to allow execution with a third-party execution engine (:issue:`61125`) - :meth:`Series.rank` and :meth:`DataFrame.rank` with numpy-nullable dtypes preserve ``NA`` values and return ``UInt64`` dtype where appropriate instead of casting ``NA`` to ``NaN`` with ``float64`` dtype (:issue:`62043`) +- :meth:`Series.round` raising ``TypeError`` for ``object`` dtype with ``pd.NA``. The result now coerces to nullable ``Float64`` and rounds as expected (:issue:`61712`). - :meth:`Series.str.get_dummies` now accepts a ``dtype`` parameter to specify the dtype of the resulting DataFrame (:issue:`47872`) - :meth:`pandas.concat` will raise a ``ValueError`` when ``ignore_index=True`` and ``keys`` is not ``None`` (:issue:`59274`) - :py:class:`frozenset` elements in pandas objects are now natively printed (:issue:`60690`) @@ -97,7 +98,7 @@ Other enhancements - Support passing a :class:`Iterable[Hashable]` input to :meth:`DataFrame.drop_duplicates` (:issue:`59237`) - Support reading Stata 102-format (Stata 1) dta files (:issue:`58978`) - Support reading Stata 110-format (Stata 7) dta files (:issue:`47176`) -- + .. --------------------------------------------------------------------------- .. _whatsnew_300.notable_bug_fixes: diff --git a/pandas/core/series.py b/pandas/core/series.py index 6ae03f2464f76..a6996867fb541 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2516,6 +2516,20 @@ def round(self, decimals: int = 0, *args, **kwargs) -> Series: """ nv.validate_round(args, kwargs) if self.dtype == "object": + # If the object-dtype Series contains pd.NA and is otherwise numeric, + # cast to nullable Float64 and round. Otherwise, fall back to the + # existing implementation to preserve prior behavior (incl. errors). + has_pd_na = self.isna().any() + if has_pd_na: + try: + converted = self.astype("Float64") + except Exception as err: + raise TypeError( + "Expected numeric dtype, got object instead." + ) from err + else: + return converted.round(decimals) + raise TypeError("Expected numeric dtype, got object instead.") new_mgr = self._mgr.round(decimals=decimals) return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__( diff --git a/pandas/tests/series/methods/test_round.py b/pandas/tests/series/methods/test_round.py index a78f77e990ae1..0779a00b2d79d 100644 --- a/pandas/tests/series/methods/test_round.py +++ b/pandas/tests/series/methods/test_round.py @@ -79,3 +79,10 @@ def test_round_dtype_object(self): msg = "Expected numeric dtype, got object instead." with pytest.raises(TypeError, match=msg): ser.round() + + def test_round_with_pd_na(self): + # GH61712 + s = Series([0.5, pd.NA], dtype="object") + result = s.round(0) + expected = Series([0.0, pd.NA], dtype="Float64") + tm.assert_series_equal(result, expected)