Skip to content

Commit d8d1a47

Browse files
DEPR: scalar index for length-1-list level groupby (#51817)
1 parent 04ec93e commit d8d1a47

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,7 @@ Deprecations
823823
- Deprecated :meth:`DataFrame.pad` in favor of :meth:`DataFrame.ffill` (:issue:`33396`)
824824
- Deprecated :meth:`DataFrame.backfill` in favor of :meth:`DataFrame.bfill` (:issue:`33396`)
825825
- Deprecated :meth:`~pandas.io.stata.StataReader.close`. Use :class:`~pandas.io.stata.StataReader` as a context manager instead (:issue:`49228`)
826+
- Deprecated producing a scalar when iterating over a :class:`.DataFrameGroupBy` or a :class:`.SeriesGroupBy` that has been grouped by a ``level`` parameter that is a list of length 1; a tuple of length one will be returned instead (:issue:`51583`)
826827

827828
.. ---------------------------------------------------------------------------
828829
.. _whatsnew_200.prior_deprecations:

pandas/core/groupby/groupby.py

+14
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class providing the base-class of operations.
7777
is_hashable,
7878
is_integer,
7979
is_integer_dtype,
80+
is_list_like,
8081
is_numeric_dtype,
8182
is_object_dtype,
8283
is_scalar,
@@ -627,6 +628,7 @@ class BaseGroupBy(PandasObject, SelectionMixin[NDFrameT], GroupByIndexingMixin):
627628
axis: AxisInt
628629
grouper: ops.BaseGrouper
629630
keys: _KeysArgType | None = None
631+
level: IndexLabel | None = None
630632
group_keys: bool | lib.NoDefault
631633

632634
@final
@@ -811,7 +813,19 @@ def __iter__(self) -> Iterator[tuple[Hashable, NDFrameT]]:
811813
for each group
812814
"""
813815
keys = self.keys
816+
level = self.level
814817
result = self.grouper.get_iterator(self._selected_obj, axis=self.axis)
818+
# error: Argument 1 to "len" has incompatible type "Hashable"; expected "Sized"
819+
if is_list_like(level) and len(level) == 1: # type: ignore[arg-type]
820+
# GH 51583
821+
warnings.warn(
822+
"Creating a Groupby object with a length-1 list-like "
823+
"level parameter will yield indexes as tuples in a future version. "
824+
"To keep indexes as scalars, create Groupby objects with "
825+
"a scalar level parameter instead.",
826+
FutureWarning,
827+
stacklevel=find_stack_level(),
828+
)
815829
if isinstance(keys, list) and len(keys) == 1:
816830
# GH#42795 - when keys is a list, return tuples even when length is 1
817831
result = (((key,), group) for key, group in result)

pandas/tests/groupby/test_groupby.py

+18
Original file line numberDiff line numberDiff line change
@@ -2708,6 +2708,24 @@ def test_single_element_list_grouping():
27082708
assert result == expected
27092709

27102710

2711+
@pytest.mark.parametrize(
2712+
"level_arg, multiindex", [([0], False), ((0,), False), ([0], True), ((0,), True)]
2713+
)
2714+
def test_single_element_listlike_level_grouping_deprecation(level_arg, multiindex):
2715+
# GH 51583
2716+
df = DataFrame({"a": [1, 2], "b": [3, 4], "c": [5, 6]}, index=["x", "y"])
2717+
if multiindex:
2718+
df = df.set_index(["a", "b"])
2719+
depr_msg = (
2720+
"Creating a Groupby object with a length-1 list-like "
2721+
"level parameter will yield indexes as tuples in a future version. "
2722+
"To keep indexes as scalars, create Groupby objects with "
2723+
"a scalar level parameter instead."
2724+
)
2725+
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
2726+
[key for key, _ in df.groupby(level=level_arg)]
2727+
2728+
27112729
@pytest.mark.parametrize("func", ["sum", "cumsum", "cumprod", "prod"])
27122730
def test_groupby_avoid_casting_to_float(func):
27132731
# GH#37493

0 commit comments

Comments
 (0)