Skip to content

Commit 3b163de

Browse files
author
Khor Chean Wei
authored
Bug fix - rename dataframe reset index (#46167)
1 parent 5c71232 commit 3b163de

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

doc/source/whatsnew/v1.5.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Other enhancements
4646
- Improved error message in :class:`~pandas.core.window.Rolling` when ``window`` is a frequency and ``NaT`` is in the rolling axis (:issue:`46087`)
4747
- :class:`Series` and :class:`DataFrame` with ``IntegerDtype`` now supports bitwise operations (:issue:`34463`)
4848
- Add ``milliseconds`` field support for :class:`~pandas.DateOffset` (:issue:`43371`)
49-
-
49+
- :meth:`DataFrame.reset_index` now accepts a ``names`` argument which renames the index names (:issue:`6878`)
5050

5151
.. ---------------------------------------------------------------------------
5252
.. _whatsnew_150.notable_bug_fixes:

pandas/core/frame.py

+28-3
Original file line numberDiff line numberDiff line change
@@ -5684,6 +5684,7 @@ def reset_index(
56845684
col_level: Hashable = ...,
56855685
col_fill: Hashable = ...,
56865686
allow_duplicates: bool | lib.NoDefault = ...,
5687+
names: Hashable | Sequence[Hashable] = None,
56875688
) -> DataFrame:
56885689
...
56895690

@@ -5696,6 +5697,7 @@ def reset_index(
56965697
col_level: Hashable = ...,
56975698
col_fill: Hashable = ...,
56985699
allow_duplicates: bool | lib.NoDefault = ...,
5700+
names: Hashable | Sequence[Hashable] = None,
56995701
) -> None:
57005702
...
57015703

@@ -5708,6 +5710,7 @@ def reset_index(
57085710
col_level: Hashable = ...,
57095711
col_fill: Hashable = ...,
57105712
allow_duplicates: bool | lib.NoDefault = ...,
5713+
names: Hashable | Sequence[Hashable] = None,
57115714
) -> None:
57125715
...
57135716

@@ -5720,6 +5723,7 @@ def reset_index(
57205723
col_level: Hashable = ...,
57215724
col_fill: Hashable = ...,
57225725
allow_duplicates: bool | lib.NoDefault = ...,
5726+
names: Hashable | Sequence[Hashable] = None,
57235727
) -> None:
57245728
...
57255729

@@ -5731,6 +5735,7 @@ def reset_index(
57315735
col_level: Hashable = ...,
57325736
col_fill: Hashable = ...,
57335737
allow_duplicates: bool | lib.NoDefault = ...,
5738+
names: Hashable | Sequence[Hashable] = None,
57345739
) -> None:
57355740
...
57365741

@@ -5743,6 +5748,7 @@ def reset_index(
57435748
col_level: Hashable = ...,
57445749
col_fill: Hashable = ...,
57455750
allow_duplicates: bool | lib.NoDefault = ...,
5751+
names: Hashable | Sequence[Hashable] = None,
57465752
) -> DataFrame | None:
57475753
...
57485754

@@ -5755,6 +5761,7 @@ def reset_index(
57555761
col_level: Hashable = 0,
57565762
col_fill: Hashable = "",
57575763
allow_duplicates: bool | lib.NoDefault = lib.no_default,
5764+
names: Hashable | Sequence[Hashable] = None,
57585765
) -> DataFrame | None:
57595766
"""
57605767
Reset the index, or a level of it.
@@ -5785,6 +5792,13 @@ def reset_index(
57855792
57865793
.. versionadded:: 1.5.0
57875794
5795+
names : int, str or 1-dimensional list, default None
5796+
Using the given string, rename the DataFrame column which contains the
5797+
index data. If the DataFrame has a MultiIndex, this has to be a list or
5798+
tuple with length equal to the number of levels.
5799+
5800+
.. versionadded:: 1.5.0
5801+
57885802
Returns
57895803
-------
57905804
DataFrame or None
@@ -5855,6 +5869,16 @@ class name
58555869
mammal lion 80.5 run
58565870
monkey NaN jump
58575871
5872+
Using the `names` parameter, choose a name for the index column:
5873+
5874+
>>> df.reset_index(names=['classes', 'names'])
5875+
classes names speed species
5876+
max type
5877+
0 bird falcon 389.0 fly
5878+
1 bird parrot 24.0 fly
5879+
2 mammal lion 80.5 run
5880+
3 mammal monkey NaN jump
5881+
58585882
If the index has multiple levels, we can reset a subset of them:
58595883
58605884
>>> df.reset_index(level='class')
@@ -5920,12 +5944,13 @@ class max type
59205944

59215945
if not drop:
59225946
to_insert: Iterable[tuple[Any, Any | None]]
5947+
5948+
default = "index" if "index" not in self else "level_0"
5949+
names = self.index._get_default_index_names(names, default)
5950+
59235951
if isinstance(self.index, MultiIndex):
5924-
names = com.fill_missing_names(self.index.names)
59255952
to_insert = zip(self.index.levels, self.index.codes)
59265953
else:
5927-
default = "index" if "index" not in self else "level_0"
5928-
names = [default] if self.index.name is None else [self.index.name]
59295954
to_insert = ((self.index, None),)
59305955

59315956
multi_col = isinstance(self.columns, MultiIndex)

pandas/core/indexes/base.py

+35
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,41 @@ def _validate_names(
17711771

17721772
return new_names
17731773

1774+
def _get_default_index_names(
1775+
self, names: Hashable | Sequence[Hashable] | None = None, default=None
1776+
) -> list[Hashable]:
1777+
"""
1778+
Get names of index.
1779+
1780+
Parameters
1781+
----------
1782+
names : int, str or 1-dimensional list, default None
1783+
Index names to set.
1784+
default : str
1785+
Default name of index.
1786+
1787+
Raises
1788+
------
1789+
TypeError
1790+
if names not str or list-like
1791+
"""
1792+
from pandas.core.indexes.multi import MultiIndex
1793+
1794+
if names is not None:
1795+
if isinstance(names, str) or isinstance(names, int):
1796+
names = [names]
1797+
1798+
if not isinstance(names, list) and names is not None:
1799+
raise ValueError("Index names must be str or 1-dimensional list")
1800+
1801+
if not names:
1802+
if isinstance(self, MultiIndex):
1803+
names = com.fill_missing_names(self.names)
1804+
else:
1805+
names = [default] if self.name is None else [self.name]
1806+
1807+
return names
1808+
17741809
def _get_names(self) -> FrozenList:
17751810
return FrozenList((self.name,))
17761811

pandas/tests/frame/methods/test_reset_index.py

+39
Original file line numberDiff line numberDiff line change
@@ -754,3 +754,42 @@ def test_reset_index_interval_columns_object_cast():
754754
columns=Index(["Year", Interval(0, 1), Interval(1, 2)]),
755755
)
756756
tm.assert_frame_equal(result, expected)
757+
758+
759+
def test_reset_index_rename(float_frame):
760+
# GH 6878
761+
result = float_frame.reset_index(names="new_name")
762+
expected = Series(float_frame.index.values, name="new_name")
763+
tm.assert_series_equal(result["new_name"], expected)
764+
765+
result = float_frame.reset_index(names=123)
766+
expected = Series(float_frame.index.values, name=123)
767+
tm.assert_series_equal(result[123], expected)
768+
769+
770+
def test_reset_index_rename_multiindex(float_frame):
771+
# GH 6878
772+
stacked_df = float_frame.stack()[::2]
773+
stacked_df = DataFrame({"foo": stacked_df, "bar": stacked_df})
774+
775+
names = ["first", "second"]
776+
stacked_df.index.names = names
777+
778+
result = stacked_df.reset_index()
779+
expected = stacked_df.reset_index(names=["new_first", "new_second"])
780+
tm.assert_series_equal(result["first"], expected["new_first"], check_names=False)
781+
tm.assert_series_equal(result["second"], expected["new_second"], check_names=False)
782+
783+
784+
def test_errorreset_index_rename(float_frame):
785+
# GH 6878
786+
stacked_df = float_frame.stack()[::2]
787+
stacked_df = DataFrame({"first": stacked_df, "second": stacked_df})
788+
789+
with pytest.raises(
790+
ValueError, match="Index names must be str or 1-dimensional list"
791+
):
792+
stacked_df.reset_index(names={"first": "new_first", "second": "new_second"})
793+
794+
with pytest.raises(IndexError, match="list index out of range"):
795+
stacked_df.reset_index(names=["new_first"])

0 commit comments

Comments
 (0)