From 8dd1d36feec9daff0f416c212569efc0031b0944 Mon Sep 17 00:00:00 2001 From: "D.S. McNeil" Date: Mon, 12 Nov 2018 14:31:54 -0500 Subject: [PATCH] BUG: Keep column level names during resample nunique (#23222) Closes https://github.com/pandas-dev/pandas/issues/23222 --- doc/source/api.rst | 1 + doc/source/whatsnew/v0.24.0.txt | 1 + pandas/core/groupby/generic.py | 1 + pandas/tests/groupby/test_function.py | 9 +++++++++ pandas/tests/test_resample.py | 8 ++++++++ 5 files changed, 20 insertions(+) diff --git a/doc/source/api.rst b/doc/source/api.rst index 665649aead33c..32cc7aa91cff1 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -2346,6 +2346,7 @@ application to columns of a specific data type. DataFrameGroupBy.idxmax DataFrameGroupBy.idxmin DataFrameGroupBy.mad + DataFrameGroupBy.nunique DataFrameGroupBy.pct_change DataFrameGroupBy.plot DataFrameGroupBy.quantile diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 20496c9fb3f31..fca9ff80fd5d9 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1335,6 +1335,7 @@ Groupby/Resample/Rolling - Bug in :meth:`DataFrame.resample` and :meth:`Series.resample` when resampling by a weekly offset (``'W'``) across a DST transition (:issue:`9119`, :issue:`21459`) - Bug in :meth:`DataFrame.expanding` in which the ``axis`` argument was not being respected during aggregations (:issue:`23372`) - Bug in :meth:`pandas.core.groupby.DataFrameGroupBy.transform` which caused missing values when the input function can accept a :class:`DataFrame` but renames it (:issue:`23455`). +- Bug in :meth:`pandas.core.groupby.DataFrameGroupBy.nunique` in which the names of column levels were lost (:issue:`23222`). Reshaping ^^^^^^^^^ diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index b0477c7d3a8ad..10a02d8c960a1 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -1568,6 +1568,7 @@ def groupby_series(obj, col=None): from pandas.core.reshape.concat import concat results = [groupby_series(obj[col], col) for col in obj.columns] results = concat(results, axis=1) + results.columns.names = obj.columns.names if not self.as_index: results.index = ibase.default_index(len(results)) diff --git a/pandas/tests/groupby/test_function.py b/pandas/tests/groupby/test_function.py index 646445623778b..ec4ae87cca8d7 100644 --- a/pandas/tests/groupby/test_function.py +++ b/pandas/tests/groupby/test_function.py @@ -892,6 +892,15 @@ def test_nunique_with_timegrouper(): tm.assert_series_equal(result, expected) +def test_nunique_preserves_column_level_names(): + # GH 23222 + test = pd.DataFrame([1, 2, 2], + columns=pd.Index(['A'], name="level_0")) + result = test.groupby([0, 0, 0]).nunique() + expected = pd.DataFrame([2], columns=test.columns) + tm.assert_frame_equal(result, expected) + + # count # -------------------------------- diff --git a/pandas/tests/test_resample.py b/pandas/tests/test_resample.py index 7e0342e8b987a..c295cfec91218 100644 --- a/pandas/tests/test_resample.py +++ b/pandas/tests/test_resample.py @@ -1947,6 +1947,14 @@ def test_resample_nunique(self): result = df.ID.groupby(pd.Grouper(freq='D')).nunique() assert_series_equal(result, expected) + def test_resample_nunique_preserves_column_level_names(self): + # GH 23222 + df = tm.makeTimeDataFrame(freq='1D').abs() + df.columns = pd.MultiIndex.from_arrays([df.columns.tolist()] * 2, + names=["lev0", "lev1"]) + result = df.resample("1h").nunique() + tm.assert_index_equal(df.columns, result.columns) + def test_resample_nunique_with_date_gap(self): # GH 13453 index = pd.date_range('1-1-2000', '2-15-2000', freq='h')