From 85c6d47e5ccc1b817ce581df0db377eafe848510 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Thu, 22 Sep 2022 06:57:10 -0700 Subject: [PATCH] BUG: pivot_table raising for nullable dtype and margins --- doc/source/whatsnew/v1.6.0.rst | 1 + pandas/core/reshape/pivot.py | 5 +++++ pandas/tests/reshape/test_pivot.py | 17 +++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 050dfacc13df0..3eea7081ae2de 100644 --- a/doc/source/whatsnew/v1.6.0.rst +++ b/doc/source/whatsnew/v1.6.0.rst @@ -239,6 +239,7 @@ Groupby/resample/rolling Reshaping ^^^^^^^^^ +- Bug in :meth:`DataFrame.pivot_table` raising ``TypeError`` for nullable dtype and ``margins=True`` (:issue:`48681`) - Bug in :meth:`DataFrame.pivot` not respecting ``None`` as column name (:issue:`48293`) - Bug in :func:`join` when ``left_on`` or ``right_on`` is or includes a :class:`CategoricalIndex` incorrectly raising ``AttributeError`` (:issue:`48464`) - diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index a55a84735699d..77c90b306870f 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -25,6 +25,7 @@ from pandas.core.dtypes.cast import maybe_downcast_to_dtype from pandas.core.dtypes.common import ( + is_extension_array_dtype, is_integer_dtype, is_list_like, is_nested_list_like, @@ -324,6 +325,10 @@ def _add_margins( row_names = result.index.names # check the result column and leave floats for dtype in set(result.dtypes): + if is_extension_array_dtype(dtype): + # Can hold NA already + continue + cols = result.select_dtypes([dtype]).columns margin_dummy[cols] = margin_dummy[cols].apply( maybe_downcast_to_dtype, args=(dtype,) diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 3fff9eb141e43..24212985b504b 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -2183,6 +2183,23 @@ def test_pivot_table_sort_false(self): ) tm.assert_frame_equal(result, expected) + def test_pivot_table_nullable_margins(self): + # GH#48681 + df = DataFrame( + {"a": "A", "b": [1, 2], "sales": Series([10, 11], dtype="Int64")} + ) + + result = df.pivot_table(index="b", columns="a", margins=True, aggfunc="sum") + expected = DataFrame( + [[10, 10], [11, 11], [21, 21]], + index=Index([1, 2, "All"], name="b"), + columns=MultiIndex.from_tuples( + [("sales", "A"), ("sales", "All")], names=[None, "a"] + ), + dtype="Int64", + ) + tm.assert_frame_equal(result, expected) + def test_pivot_table_sort_false_with_multiple_values(self): df = DataFrame( {