From 0930517ec643dd5aa08e23af2880d314f5143a0f Mon Sep 17 00:00:00 2001 From: sharkipelago Date: Fri, 20 Jun 2025 15:41:19 -0400 Subject: [PATCH 1/3] added TypeError if object dtypes are dtected in dataframe --- doc/source/whatsnew/v3.0.0.rst | 1 + pandas/core/frame.py | 7 +++-- pandas/tests/frame/methods/test_round.py | 36 ++++++++---------------- 3 files changed, 18 insertions(+), 26 deletions(-) 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..82474c740a4ec 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(s)" + ) 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/frame/methods/test_round.py b/pandas/tests/frame/methods/test_round.py index a96df27b48d7d..1fdd616caf578 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,15 @@ 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( + { + "a": [1.2234242333234, 323432.3243423, np.nan], + "b": ["a", "b", "c"], + } + ) + msg = "All columns must be numeric dtype, but got object dtype column\\(s\\)" + with pytest.raises(TypeError, match=msg): + df.round() From 3ebeec7a26af59da8c378389145319932b061117 Mon Sep 17 00:00:00 2001 From: sharkipelago Date: Fri, 20 Jun 2025 17:26:20 -0400 Subject: [PATCH 2/3] cleaned up test --- pandas/core/frame.py | 2 +- pandas/tests/frame/methods/test_round.py | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 82474c740a4ec..70569fc687a8e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -11229,7 +11229,7 @@ def _series_round(ser: Series, decimals: int) -> Series: nv.validate_round(args, kwargs) if "object" in self.dtypes.values: raise TypeError( - "All columns must be numeric dtype, but got object dtype column(s)" + "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: diff --git a/pandas/tests/frame/methods/test_round.py b/pandas/tests/frame/methods/test_round.py index 1fdd616caf578..b09d4f8dbbfc4 100644 --- a/pandas/tests/frame/methods/test_round.py +++ b/pandas/tests/frame/methods/test_round.py @@ -202,12 +202,7 @@ def test_round_empty_not_input(self): def test_round_non_numeric_columns(self): # GH#61679 - df = DataFrame( - { - "a": [1.2234242333234, 323432.3243423, np.nan], - "b": ["a", "b", "c"], - } - ) - msg = "All columns must be numeric dtype, but got object dtype column\\(s\\)" + 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() From 1244bde2c534e8ad56c00729a6d57970f6b58481 Mon Sep 17 00:00:00 2001 From: sharkipelago Date: Sun, 22 Jun 2025 09:38:21 -0400 Subject: [PATCH 3/3] updated copy_view test to reflect that round should only be used on numeric dfs --- pandas/tests/copy_view/test_methods.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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)