Skip to content

Commit 15b8898

Browse files
authored
Bug in DataFrame.loc returning elements in wrong order when indexer is differently ordered than object (#37992)
1 parent 61f67b6 commit 15b8898

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ Indexing
621621
- Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`)
622622
- Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`)
623623
- Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`)
624+
- Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`)
624625
- Bug in :meth:`DataFrame.loc` and :meth:`DataFrame.__getitem__` raising ``KeyError`` when columns were :class:`MultiIndex` with only one level (:issue:`29749`)
625626

626627
Missing

pandas/core/indexes/multi.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -3262,7 +3262,7 @@ def _update_indexer(
32623262
self._get_level_indexer(x, level=i, indexer=indexer)
32633263
)
32643264
indexers = (idxrs if indexers is None else indexers).union(
3265-
idxrs
3265+
idxrs, sort=False
32663266
)
32673267
except KeyError:
32683268

@@ -3349,6 +3349,9 @@ def _reorder_indexer(
33493349
# order they appears in a list-like sequence
33503350
# This mapping is then use to reorder the indexer
33513351
for i, k in enumerate(seq):
3352+
if is_scalar(k):
3353+
# GH#34603 we want to treat a scalar the same as an all equal list
3354+
k = [k]
33523355
if com.is_bool_indexer(k):
33533356
new_order = np.arange(n)[indexer]
33543357
elif is_list_like(k):
@@ -3362,6 +3365,9 @@ def _reorder_indexer(
33623365
key_order_map[level_indexer] = np.arange(len(level_indexer))
33633366

33643367
new_order = key_order_map[self.codes[i][indexer]]
3368+
elif isinstance(k, slice) and k.start is None and k.stop is None:
3369+
# slice(None) should not determine order GH#31330
3370+
new_order = np.ones((n,))[indexer]
33653371
else:
33663372
# For all other case, use the same order as the level
33673373
new_order = np.arange(n)[indexer]

pandas/tests/indexing/multiindex/test_loc.py

+27
Original file line numberDiff line numberDiff line change
@@ -668,3 +668,30 @@ def test_get_loc_datetime_index():
668668
# Check if get_loc matches for Index and MultiIndex
669669
assert mi.get_loc("2001-01") == slice(0, 31, None)
670670
assert index.get_loc("2001-01") == slice(0, 31, None)
671+
672+
673+
def test_loc_setitem_indexer_differently_ordered():
674+
# GH#34603
675+
mi = MultiIndex.from_product([["a", "b"], [0, 1]])
676+
df = DataFrame([[1, 2], [3, 4], [5, 6], [7, 8]], index=mi)
677+
678+
indexer = ("a", [1, 0])
679+
df.loc[indexer, :] = np.array([[9, 10], [11, 12]])
680+
expected = DataFrame([[11, 12], [9, 10], [5, 6], [7, 8]], index=mi)
681+
tm.assert_frame_equal(df, expected)
682+
683+
684+
def test_loc_getitem_index_differently_ordered_slice_none():
685+
# GH#31330
686+
df = DataFrame(
687+
[[1, 2], [3, 4], [5, 6], [7, 8]],
688+
index=[["a", "a", "b", "b"], [1, 2, 1, 2]],
689+
columns=["a", "b"],
690+
)
691+
result = df.loc[(slice(None), [2, 1]), :]
692+
expected = DataFrame(
693+
[[3, 4], [7, 8], [1, 2], [5, 6]],
694+
index=[["a", "b", "a", "b"], [2, 2, 1, 1]],
695+
columns=["a", "b"],
696+
)
697+
tm.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)