diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f26c6506477d4..dddf81fa59aff 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -122,6 +122,24 @@ These improvements also fixed certain bugs in groupby: - :meth:`.DataFrameGroupBy.sum` would have incorrect values when there are multiple groupings, unobserved groups, and non-numeric data (:issue:`43891`) - :meth:`.DataFrameGroupBy.value_counts` would produce incorrect results when used with some categorical and some non-categorical groupings and ``observed=False`` (:issue:`56016`) +.. _whatsnew_300.notable_bug_fixes.xs_function_default_level: + +`DataFrame.xs()` did not work as expected when level was not specified by default. (:issue:`59098`) + +ex. +.. ipython:: python + + df = pd.DataFrame(dict(i=[1,2,3], j=[1,1,2], x=[10, 100, 1000])).set_index(["i", "j"]) + + key = (1, 1) + + # Returns DataFrame as expected: + result1 = df.xs(key, drop_level=False, level=list(range(len(key)))) + + # Returns Series, but DataFrame was expected: + result2 = df.xs(key, drop_level=False) + + .. _whatsnew_300.notable_bug_fixes.notable_bug_fix2: notable_bug_fix2 diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0f0078fc3398b..de826c731d159 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2,6 +2,7 @@ from __future__ import annotations import collections +import collections.abc from copy import deepcopy import datetime as dt from functools import partial @@ -4126,7 +4127,12 @@ class animal locomotion index = self.index if isinstance(index, MultiIndex): - loc, new_index = index._get_loc_level(key, level=0) + level = range(len(key)) if isinstance(key, collections.abc.Sequence) else 0 + loc, new_index = index.get_loc_level( + key, + level=level, + drop_level=drop_level + ) if not drop_level: if lib.is_integer(loc): # Slice index must be an integer or None diff --git a/pandas/tests/series/indexing/test_xs.py b/pandas/tests/series/indexing/test_xs.py index a67f3ec708f24..00a008a1a7fbb 100644 --- a/pandas/tests/series/indexing/test_xs.py +++ b/pandas/tests/series/indexing/test_xs.py @@ -2,6 +2,7 @@ import pytest from pandas import ( + DataFrame, MultiIndex, Series, date_range, @@ -80,3 +81,18 @@ def test_xs_key_as_list(self): with pytest.raises(TypeError, match="list keys are not supported"): ser.xs(["a"], axis=0, drop_level=False) + + def test_xs_default_level(self): + # GH#59098 + df = DataFrame( + {"i": [1,2,3], "j": [1,1,2], "x": [10, 100, 1000]} + ).set_index(["i", "j"]) + key = (1, 1) + + # Both scenarios should return DataFrame + result_with_level = df.xs(key, drop_level=False, level=list(range(len(key)))) + result_with_default = df.xs(key, drop_level=False) + + assert type(result_with_default) == DataFrame + assert type(result_with_level) == type(result_with_default) + tm.assert_equal(result_with_level, result_with_default)