Skip to content

Commit 3c3492f

Browse files
committed
Added nunique section to whatsnew, removed series logic from DataFrameGroupby.nunique
1 parent 5eb636d commit 3c3492f

File tree

2 files changed

+50
-24
lines changed

2 files changed

+50
-24
lines changed

doc/source/whatsnew/v1.1.0.rst

+29
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,35 @@ Assignment to multiple columns of a :class:`DataFrame` when some of the columns
559559
df[['a', 'c']] = 1
560560
df
561561
562+
.. _whatsnew_110.api_breaking.groupby_nunique:
563+
564+
Using groupby with ``nunique`` and ``as_index=True``
565+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
566+
567+
Using :meth:`DataFrame.groupby` with ``as_index=True`` and the aggregation ``nunique`` would include the grouping column(s) in the columns of the result. Now, the grouping columns only appear in the index. This is now consistent with other aggregation functions. (:issue:`32579`)
568+
569+
.. ipython:: python
570+
571+
df = pd.DataFrame({"a": ["x", "x", "y", "y"], "b": [1, 1, 2, 3]})
572+
df
573+
574+
*Previous behavior*:
575+
576+
.. code-block:: ipython
577+
578+
In [3]: df.groupby("a", as_index=True).nunique()
579+
Out[4]:
580+
a b
581+
a
582+
x 1 1
583+
y 1 2
584+
585+
*New behavior*:
586+
587+
.. ipython:: python
588+
589+
df.groupby("a", as_index=True).nunique()
590+
562591
.. _whatsnew_110.api_breaking.groupby_as_index_false:
563592

564593
Using groupby with ``as_index=False``

pandas/core/groupby/generic.py

+21-24
Original file line numberDiff line numberDiff line change
@@ -1877,39 +1877,36 @@ def nunique(self, dropna: bool = True):
18771877
4 ham 5 x
18781878
5 ham 5 y
18791879
"""
1880-
obj = self._obj_with_exclusions
1880+
from pandas.core.reshape.concat import concat
18811881

1882-
def groupby_series(obj, col=None):
1883-
return SeriesGroupBy(obj, selection=col, grouper=self.grouper).nunique(
1884-
dropna=dropna
1885-
)
1882+
# TODO: this is duplicative of how GroupBy naturally works
1883+
# Try to consolidate with normal wrapping functions
18861884

1887-
if isinstance(obj, Series):
1888-
results = groupby_series(obj)
1885+
obj = self._obj_with_exclusions
1886+
axis_number = obj._get_axis_number(self.axis)
1887+
other_axis = int(not axis_number)
1888+
if axis_number == 0:
1889+
iter_func = obj.items
18891890
else:
1890-
# TODO: this is duplicative of how GroupBy naturally works
1891-
# Try to consolidate with normal wrapping functions
1892-
from pandas.core.reshape.concat import concat
1891+
iter_func = obj.iterrows
18931892

1894-
axis_number = obj._get_axis_number(self.axis)
1895-
other_axis = int(not axis_number)
1896-
if axis_number == 0:
1897-
iter_func = obj.items
1898-
else:
1899-
iter_func = obj.iterrows
1900-
1901-
results = [groupby_series(content, label) for label, content in iter_func()]
1902-
results = concat(results, axis=1)
1893+
results = concat(
1894+
[
1895+
SeriesGroupBy(content, selection=label, grouper=self.grouper).nunique(
1896+
dropna
1897+
)
1898+
for label, content in iter_func()
1899+
],
1900+
axis=1,
1901+
)
19031902

1904-
if axis_number == 1:
1905-
results = results.T
1903+
if axis_number == 1:
1904+
results = results.T
19061905

1907-
results._get_axis(other_axis).names = obj._get_axis(other_axis).names
1906+
results._get_axis(other_axis).names = obj._get_axis(other_axis).names
19081907

19091908
if not self.as_index:
19101909
results.index = ibase.default_index(len(results))
1911-
if results.ndim == 1:
1912-
results = results.to_frame()
19131910
self._insert_inaxis_grouper_inplace(results)
19141911
return results
19151912

0 commit comments

Comments
 (0)