Skip to content

Commit ccc25db

Browse files
phoflmeeseeksmachine
authored andcommitted
Backport PR pandas-dev#39071: Regression in loc.setitem raising ValueError with unordered MultiIndex columns and scalar indexer
1 parent 2ee88b8 commit ccc25db

File tree

3 files changed

+22
-3
lines changed

3 files changed

+22
-3
lines changed

doc/source/whatsnew/v1.2.1.rst

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Fixed regressions
2222
- Fixed regression in :meth:`DataFrame.any` and :meth:`DataFrame.all` not returning a result for tz-aware ``datetime64`` columns (:issue:`38723`)
2323
- Fixed regression in :meth:`DataFrame.__setitem__` raising ``ValueError`` when expanding :class:`DataFrame` and new column is from type ``"0 - name"`` (:issue:`39010`)
2424
- Fixed regression in :meth:`.GroupBy.sem` where the presence of non-numeric columns would cause an error instead of being dropped (:issue:`38774`)
25+
- Fixed regression in :meth:`DataFrame.loc.__setitem__` raising ``ValueError`` when :class:`DataFrame` has unsorted :class:`MultiIndex` columns and indexer is a scalar (:issue:`38601`)
2526
- Fixed regression in :func:`read_excel` with non-rawbyte file handles (:issue:`38788`)
2627
- Bug in :meth:`read_csv` with ``float_precision="high"`` caused segfault or wrong parsing of long exponent strings. This resulted in a regression in some cases as the default for ``float_precision`` was changed in pandas 1.2.0 (:issue:`38753`)
2728
- Fixed regression in :meth:`DataFrameGroupBy.diff` raising for ``int8`` and ``int16`` columns (:issue:`39050`)

pandas/core/indexing.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from pandas.core.dtypes.common import (
1515
is_array_like,
16+
is_bool_dtype,
1617
is_hashable,
1718
is_integer,
1819
is_iterator,
@@ -1925,12 +1926,14 @@ def _ensure_iterable_column_indexer(self, column_indexer):
19251926
"""
19261927
Ensure that our column indexer is something that can be iterated over.
19271928
"""
1928-
# Ensure we have something we can iterate over
19291929
if is_integer(column_indexer):
19301930
ilocs = [column_indexer]
19311931
elif isinstance(column_indexer, slice):
1932-
ri = Index(range(len(self.obj.columns)))
1933-
ilocs = ri[column_indexer]
1932+
ilocs = np.arange(len(self.obj.columns))[column_indexer]
1933+
elif isinstance(column_indexer, np.ndarray) and is_bool_dtype(
1934+
column_indexer.dtype
1935+
):
1936+
ilocs = np.arange(len(column_indexer))[column_indexer]
19341937
else:
19351938
ilocs = column_indexer
19361939
return ilocs

pandas/tests/frame/indexing/test_indexing.py

+15
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,21 @@ def test_getitem_interval_index_partial_indexing(self):
16821682
res = df.loc[:, 0.5]
16831683
tm.assert_series_equal(res, expected)
16841684

1685+
@pytest.mark.parametrize("indexer", ["A", ["A"], ("A", slice(None))])
1686+
def test_setitem_unsorted_multiindex_columns(self, indexer):
1687+
# GH#38601
1688+
mi = MultiIndex.from_tuples([("A", 4), ("B", "3"), ("A", "2")])
1689+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=mi)
1690+
obj = df.copy()
1691+
obj.loc[:, indexer] = np.zeros((2, 2), dtype=int)
1692+
expected = DataFrame([[0, 2, 0], [0, 5, 0]], columns=mi)
1693+
tm.assert_frame_equal(obj, expected)
1694+
1695+
df = df.sort_index(1)
1696+
df.loc[:, indexer] = np.zeros((2, 2), dtype=int)
1697+
expected = expected.sort_index(1)
1698+
tm.assert_frame_equal(df, expected)
1699+
16851700

16861701
class TestDataFrameIndexingUInt64:
16871702
def test_setitem(self, uint64_frame):

0 commit comments

Comments
 (0)