diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 8d3ac0e396430..4402ae0f860ea 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -73,6 +73,7 @@ Other enhancements - :meth:`.DataFrameGroupBy.transform`, :meth:`.SeriesGroupBy.transform`, :meth:`.DataFrameGroupBy.agg`, :meth:`.SeriesGroupBy.agg`, :meth:`.SeriesGroupBy.apply`, :meth:`.DataFrameGroupBy.apply` now support ``kurt`` (:issue:`40139`) - :meth:`DataFrame.apply` supports using third-party execution engines like the Bodo.ai JIT compiler (:issue:`60668`) - :meth:`DataFrame.iloc` and :meth:`Series.iloc` now support boolean masks in ``__getitem__`` for more consistent indexing behavior (:issue:`60994`) +- :meth:`DataFrame.round` now raises a ``Type Error`` if any columns are non-numeric (:issue:`61679`) - :meth:`DataFrameGroupBy.transform`, :meth:`SeriesGroupBy.transform`, :meth:`DataFrameGroupBy.agg`, :meth:`SeriesGroupBy.agg`, :meth:`RollingGroupby.apply`, :meth:`ExpandingGroupby.apply`, :meth:`Rolling.apply`, :meth:`Expanding.apply`, :meth:`DataFrame.apply` with ``engine="numba"`` now supports positional arguments passed as kwargs (:issue:`58995`) - :meth:`Rolling.agg`, :meth:`Expanding.agg` and :meth:`ExponentialMovingWindow.agg` now accept :class:`NamedAgg` aggregations through ``**kwargs`` (:issue:`28333`) - :meth:`Series.map` can now accept kwargs to pass on to func (:issue:`59814`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8053c17437c5e..70569fc687a8e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -11152,7 +11152,7 @@ def round( Returns ------- DataFrame - A DataFrame with the affected columns rounded to the specified + A DataFrame with columns rounded to the specified number of decimal places. See Also @@ -11227,7 +11227,10 @@ def _series_round(ser: Series, decimals: int) -> Series: return ser nv.validate_round(args, kwargs) - + if "object" in self.dtypes.values: + raise TypeError( + "All columns must be numeric dtype, but got object dtype column" + ) if isinstance(decimals, (dict, Series)): if isinstance(decimals, Series) and not decimals.index.is_unique: raise ValueError("Index of decimals must be unique") diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py index 250697c91ff13..1e0d98b51134f 100644 --- a/pandas/tests/copy_view/test_methods.py +++ b/pandas/tests/copy_view/test_methods.py @@ -911,11 +911,11 @@ def test_sort_values_inplace(obj, kwargs): @pytest.mark.parametrize("decimals", [-1, 0, 1]) def test_round(decimals): - df = DataFrame({"a": [1, 2], "b": "c"}) + df = DataFrame({"a": [1, 2], "b": [3.3, 4.4]}) df_orig = df.copy() df2 = df.round(decimals=decimals) - assert tm.shares_memory(get_array(df2, "b"), get_array(df, "b")) + assert not tm.shares_memory(get_array(df2, "b"), get_array(df, "b")) # TODO: Make inplace by using out parameter of ndarray.round? if decimals >= 0: # Ensure lazy copy if no-op @@ -923,8 +923,8 @@ def test_round(decimals): else: assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) - df2.iloc[0, 1] = "d" - df2.iloc[0, 0] = 4 + df2.iloc[0, 1] = 6.6 + df2.iloc[0, 0] = 5 assert not np.shares_memory(get_array(df2, "b"), get_array(df, "b")) assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) tm.assert_frame_equal(df, df_orig) diff --git a/pandas/tests/frame/methods/test_round.py b/pandas/tests/frame/methods/test_round.py index a96df27b48d7d..b09d4f8dbbfc4 100644 --- a/pandas/tests/frame/methods/test_round.py +++ b/pandas/tests/frame/methods/test_round.py @@ -5,7 +5,6 @@ from pandas import ( DataFrame, Series, - date_range, ) import pandas._testing as tm @@ -143,29 +142,6 @@ def test_round_numpy_with_nan(self): expected = Series([2.0, np.nan, 0.0]).to_frame() tm.assert_frame_equal(result, expected) - def test_round_mixed_type(self): - # GH#11885 - df = DataFrame( - { - "col1": [1.1, 2.2, 3.3, 4.4], - "col2": ["1", "a", "c", "f"], - "col3": date_range("20111111", periods=4), - } - ) - round_0 = DataFrame( - { - "col1": [1.0, 2.0, 3.0, 4.0], - "col2": ["1", "a", "c", "f"], - "col3": date_range("20111111", periods=4), - } - ) - tm.assert_frame_equal(df.round(), round_0) - tm.assert_frame_equal(df.round(1), df) - tm.assert_frame_equal(df.round({"col1": 1}), df) - tm.assert_frame_equal(df.round({"col1": 0}), round_0) - tm.assert_frame_equal(df.round({"col1": 0, "col2": 1}), round_0) - tm.assert_frame_equal(df.round({"col3": 1}), df) - def test_round_with_duplicate_columns(self): # GH#11611 @@ -223,3 +199,10 @@ def test_round_empty_not_input(self): result = df.round() tm.assert_frame_equal(df, result) assert df is not result + + def test_round_non_numeric_columns(self): + # GH#61679 + df = DataFrame({"col1": [1.22, 10.32, 3.54], "col2": ["a", "b", "c"]}) + msg = "All columns must be numeric dtype, but got object dtype column" + with pytest.raises(TypeError, match=msg): + df.round()