Skip to content

Commit 5c111cb

Browse files
authored
BUG: Bug in xs ignored droplevel (#37776)
1 parent 0e59178 commit 5c111cb

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ Indexing
475475
- Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` raises when numeric label was given for object :class:`Index` although label was in :class:`Index` (:issue:`26491`)
476476
- Bug in :meth:`DataFrame.loc` returned requested key plus missing values when ``loc`` was applied to single level from :class:`MultiIndex` (:issue:`27104`)
477477
- Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`CategoricalIndex` using a listlike indexer containing NA values (:issue:`37722`)
478+
- Bug in :meth:`DataFrame.xs` ignored ``droplevel=False`` for columns (:issue:`19056`)
478479

479480
Missing
480481
^^^^^^^

pandas/core/generic.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -3708,18 +3708,21 @@ class animal locomotion
37083708
return result
37093709

37103710
if axis == 1:
3711-
return self[key]
3711+
if drop_level:
3712+
return self[key]
3713+
index = self.columns
3714+
else:
3715+
index = self.index
37123716

3713-
index = self.index
37143717
if isinstance(index, MultiIndex):
37153718
try:
3716-
loc, new_index = self.index._get_loc_level(
3719+
loc, new_index = index._get_loc_level(
37173720
key, level=0, drop_level=drop_level
37183721
)
37193722
except TypeError as e:
37203723
raise TypeError(f"Expected label or tuple of labels, got {key}") from e
37213724
else:
3722-
loc = self.index.get_loc(key)
3725+
loc = index.get_loc(key)
37233726

37243727
if isinstance(loc, np.ndarray):
37253728
if loc.dtype == np.bool_:
@@ -3729,9 +3732,9 @@ class animal locomotion
37293732
return self._take_with_is_copy(loc, axis=axis)
37303733

37313734
if not is_scalar(loc):
3732-
new_index = self.index[loc]
3735+
new_index = index[loc]
37333736

3734-
if is_scalar(loc):
3737+
if is_scalar(loc) and axis == 0:
37353738
# In this case loc should be an integer
37363739
if self.ndim == 1:
37373740
# if we encounter an array-like and we only have 1 dim
@@ -3747,7 +3750,10 @@ class animal locomotion
37473750
name=self.index[loc],
37483751
dtype=new_values.dtype,
37493752
)
3750-
3753+
elif is_scalar(loc):
3754+
result = self.iloc[:, [loc]]
3755+
elif axis == 1:
3756+
result = self.iloc[:, loc]
37513757
else:
37523758
result = self.iloc[loc]
37533759
result.index = new_index

pandas/tests/frame/indexing/test_xs.py

+22
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,25 @@ def test_xs_levels_raises(self, klass):
297297
msg = "Index must be a MultiIndex"
298298
with pytest.raises(TypeError, match=msg):
299299
obj.xs(0, level="as")
300+
301+
def test_xs_multiindex_droplevel_false(self):
302+
# GH#19056
303+
mi = MultiIndex.from_tuples(
304+
[("a", "x"), ("a", "y"), ("b", "x")], names=["level1", "level2"]
305+
)
306+
df = DataFrame([[1, 2, 3]], columns=mi)
307+
result = df.xs("a", axis=1, drop_level=False)
308+
expected = DataFrame(
309+
[[1, 2]],
310+
columns=MultiIndex.from_tuples(
311+
[("a", "x"), ("a", "y")], names=["level1", "level2"]
312+
),
313+
)
314+
tm.assert_frame_equal(result, expected)
315+
316+
def test_xs_droplevel_false(self):
317+
# GH#19056
318+
df = DataFrame([[1, 2, 3]], columns=Index(["a", "b", "c"]))
319+
result = df.xs("a", axis=1, drop_level=False)
320+
expected = DataFrame({"a": [1]})
321+
tm.assert_frame_equal(result, expected)

pandas/tests/series/indexing/test_xs.py

+15
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,18 @@ def test_series_getitem_multiindex_xs(xs):
5050

5151
result = ser.xs("20130903", level=1)
5252
tm.assert_series_equal(result, expected)
53+
54+
def test_series_xs_droplevel_false(self):
55+
# GH: 19056
56+
mi = MultiIndex.from_tuples(
57+
[("a", "x"), ("a", "y"), ("b", "x")], names=["level1", "level2"]
58+
)
59+
df = Series([1, 1, 1], index=mi)
60+
result = df.xs("a", axis=0, drop_level=False)
61+
expected = Series(
62+
[1, 1],
63+
index=MultiIndex.from_tuples(
64+
[("a", "x"), ("a", "y")], names=["level1", "level2"]
65+
),
66+
)
67+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)