Skip to content

Commit 8af96fc

Browse files
authored
DEPR: Not passing tuple to get_group when grouping on length-1 list-likes (#54155)
* DEPR: Not passing tuple to get_group when grouping on length-1 list-likes * test fixup * Move whatsnew note; fixup in cookbook * fixups * fixup
1 parent 14a6c9a commit 8af96fc

File tree

7 files changed

+59
-8
lines changed

7 files changed

+59
-8
lines changed

doc/source/user_guide/cookbook.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ Unlike agg, apply's callable is passed a sub-DataFrame which gives you access to
466466

467467
.. ipython:: python
468468
469-
gb = df.groupby(["animal"])
469+
gb = df.groupby("animal")
470470
gb.get_group("cat")
471471
472472
`Apply to different items in a group

doc/source/user_guide/groupby.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ For example, the groups created by ``groupby()`` below are in the order they app
211211
.. ipython:: python
212212
213213
df3 = pd.DataFrame({"X": ["A", "B", "A", "B"], "Y": [1, 4, 3, 2]})
214-
df3.groupby(["X"]).get_group("A")
214+
df3.groupby("X").get_group("A")
215215
216-
df3.groupby(["X"]).get_group("B")
216+
df3.groupby(["X"]).get_group(("B",))
217217
218218
219219
.. _groupby.dropna:

doc/source/whatsnew/v2.2.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ Deprecations
9898
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_markdown` except ``buf``. (:issue:`54229`)
9999
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_pickle` except ``path``. (:issue:`54229`)
100100
- Deprecated allowing non-keyword arguments in :meth:`DataFrame.to_string` except ``buf``. (:issue:`54229`)
101+
- Deprecated not passing a tuple to :class:`DataFrameGroupBy.get_group` or :class:`SeriesGroupBy.get_group` when grouping by a length-1 list-like (:issue:`25971`)
102+
101103
-
102104

103105
.. ---------------------------------------------------------------------------

pandas/core/groupby/groupby.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ def get_group(self, name, obj=None) -> DataFrame | Series:
10331033
owl 1 2 3
10341034
toucan 1 5 6
10351035
eagle 7 8 9
1036-
>>> df.groupby(by=["a"]).get_group(1)
1036+
>>> df.groupby(by=["a"]).get_group((1,))
10371037
a b c
10381038
owl 1 2 3
10391039
toucan 1 5 6
@@ -1053,6 +1053,26 @@ def get_group(self, name, obj=None) -> DataFrame | Series:
10531053
2023-01-15 2
10541054
dtype: int64
10551055
"""
1056+
keys = self.keys
1057+
level = self.level
1058+
# mypy doesn't recognize level/keys as being sized when passed to len
1059+
if (is_list_like(level) and len(level) == 1) or ( # type: ignore[arg-type]
1060+
is_list_like(keys) and len(keys) == 1 # type: ignore[arg-type]
1061+
):
1062+
# GH#25971
1063+
if isinstance(name, tuple) and len(name) == 1:
1064+
# Allow users to pass tuples of length 1 to silence warning
1065+
name = name[0]
1066+
elif not isinstance(name, tuple):
1067+
warnings.warn(
1068+
"When grouping with a length-1 list-like, "
1069+
"you will need to pass a length-1 tuple to get_group in a future "
1070+
"version of pandas. Pass `(name,)` instead of `name` to silence "
1071+
"this warning.",
1072+
FutureWarning,
1073+
stacklevel=find_stack_level(),
1074+
)
1075+
10561076
inds = self._get_index(name)
10571077
if not len(inds):
10581078
raise KeyError(name)

pandas/tests/groupby/test_categorical.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,10 @@ def test_level_get_group(observed):
268268
names=["Index1", "Index2"],
269269
),
270270
)
271-
result = g.get_group("a")
271+
msg = "you will need to pass a length-1 tuple"
272+
with tm.assert_produces_warning(FutureWarning, match=msg):
273+
# GH#25971 - warn when not passing a length-1 tuple
274+
result = g.get_group("a")
272275

273276
tm.assert_frame_equal(result, expected)
274277

pandas/tests/groupby/test_groupby.py

+28
Original file line numberDiff line numberDiff line change
@@ -3159,3 +3159,31 @@ def test_groupby_series_with_datetimeindex_month_name():
31593159
expected = Series([2, 1], name="jan")
31603160
expected.index.name = "jan"
31613161
tm.assert_series_equal(result, expected)
3162+
3163+
3164+
@pytest.mark.parametrize("test_series", [True, False])
3165+
@pytest.mark.parametrize(
3166+
"kwarg, value, name, warn",
3167+
[
3168+
("by", "a", 1, None),
3169+
("by", ["a"], 1, FutureWarning),
3170+
("by", ["a"], (1,), None),
3171+
("level", 0, 1, None),
3172+
("level", [0], 1, FutureWarning),
3173+
("level", [0], (1,), None),
3174+
],
3175+
)
3176+
def test_depr_get_group_len_1_list_likes(test_series, kwarg, value, name, warn):
3177+
# GH#25971
3178+
obj = DataFrame({"b": [3, 4, 5]}, index=Index([1, 1, 2], name="a"))
3179+
if test_series:
3180+
obj = obj["b"]
3181+
gb = obj.groupby(**{kwarg: value})
3182+
msg = "you will need to pass a length-1 tuple"
3183+
with tm.assert_produces_warning(warn, match=msg):
3184+
result = gb.get_group(name)
3185+
if test_series:
3186+
expected = Series([3, 4], index=Index([1, 1], name="a"), name="b")
3187+
else:
3188+
expected = DataFrame({"b": [3, 4]}, index=Index([1, 1], name="a"))
3189+
tm.assert_equal(result, expected)

pandas/tests/reshape/merge/test_join.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,7 @@ def _check_join(left, right, result, join_col, how="left", lsuffix="_x", rsuffix
813813
left_grouped = left.groupby(join_col)
814814
right_grouped = right.groupby(join_col)
815815

816-
for group_key, group in result.groupby(
817-
join_col if len(join_col) > 1 else join_col[0]
818-
):
816+
for group_key, group in result.groupby(join_col):
819817
l_joined = _restrict_to_columns(group, left.columns, lsuffix)
820818
r_joined = _restrict_to_columns(group, right.columns, rsuffix)
821819

0 commit comments

Comments
 (0)