Skip to content

Commit 0fd6ca7

Browse files
committed
Improve Index._transform_index level handling
1 parent 391107a commit 0fd6ca7

File tree

3 files changed

+18
-6
lines changed

3 files changed

+18
-6
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ Other
909909
- Bug in :meth:`DataFrame.sort_values` where sorting by a column explicitly named ``None`` raised a ``KeyError`` instead of sorting by the column as expected. (:issue:`61512`)
910910
- Bug in :meth:`DataFrame.transform` that was returning the wrong order unless the index was monotonically increasing. (:issue:`57069`)
911911
- Bug in :meth:`DataFrame.where` where using a non-bool type array in the function would return a ``ValueError`` instead of a ``TypeError`` (:issue:`56330`)
912+
- Bug in :meth:`Index._transform_index` where transformations are applied across all levels one by one even when a level is not specified (:issue:`55169`)
912913
- Bug in :meth:`Index.sort_values` when passing a key function that turns values into tuples, e.g. ``key=natsort.natsort_key``, would raise ``TypeError`` (:issue:`56081`)
913914
- Bug in :meth:`MultiIndex.fillna` error message was referring to ``isna`` instead of ``fillna`` (:issue:`60974`)
914915
- Bug in :meth:`Series.describe` where median percentile was always included when the ``percentiles`` argument was passed (:issue:`60550`).

pandas/core/indexes/base.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6429,12 +6429,15 @@ def _transform_index(self, func, *, level=None) -> Index:
64296429
Only apply function to one level of the MultiIndex if level is specified.
64306430
"""
64316431
if isinstance(self, ABCMultiIndex):
6432-
values = [
6433-
self.get_level_values(i).map(func)
6434-
if i == level or level is None
6435-
else self.get_level_values(i)
6436-
for i in range(self.nlevels)
6437-
]
6432+
if level is None:
6433+
return self.map(func)
6434+
else:
6435+
values = [
6436+
self.get_level_values(i).map(func)
6437+
if i == level
6438+
else self.get_level_values(i)
6439+
for i in range(self.nlevels)
6440+
]
64386441
return type(self).from_arrays(values)
64396442
else:
64406443
items = [func(x) for x in self]

pandas/tests/frame/methods/test_rename.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ def test_rename_multiindex(self):
164164
renamed = df.rename(index={"foo1": "foo3", "bar2": "bar3"}, level=0)
165165
tm.assert_index_equal(renamed.index, new_index)
166166

167+
def test_rename_multiindex_tuples_with_checks(self):
168+
df = DataFrame({("a", "count"): [1, 2], ("a", "sum"): [3, 4]})
169+
renamed = df.rename(
170+
columns={("a", "count"): ("b", "number_of"), ("a", "sum"): ("b", "total")}, errors="raise"
171+
)
172+
new_columns = MultiIndex.from_tuples([("b", "number_of"), ("b", "total")])
173+
tm.assert_index_equal(renamed.columns, new_columns)
174+
167175
def test_rename_nocopy(self, float_frame):
168176
renamed = float_frame.rename(columns={"C": "foo"})
169177

0 commit comments

Comments
 (0)