Skip to content

Commit da80247

Browse files
authored
PERF: Allow Index.to_frame to return RangeIndex columns (#58018)
1 parent 3904711 commit da80247

File tree

4 files changed

+36
-7
lines changed

4 files changed

+36
-7
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ Performance improvements
299299
- Performance improvement in :meth:`DataFrameGroupBy.ffill`, :meth:`DataFrameGroupBy.bfill`, :meth:`SeriesGroupBy.ffill`, and :meth:`SeriesGroupBy.bfill` (:issue:`56902`)
300300
- Performance improvement in :meth:`Index.join` by propagating cached attributes in cases where the result matches one of the inputs (:issue:`57023`)
301301
- Performance improvement in :meth:`Index.take` when ``indices`` is a full range indexer from zero to length of index (:issue:`56806`)
302+
- Performance improvement in :meth:`Index.to_frame` returning a :class:`RangeIndex` columns of a :class:`Index` when possible. (:issue:`58018`)
302303
- Performance improvement in :meth:`MultiIndex.equals` for equal length indexes (:issue:`56990`)
303304
- Performance improvement in :meth:`RangeIndex.__getitem__` with a boolean mask or integers returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57588`)
304305
- Performance improvement in :meth:`RangeIndex.append` when appending the same index (:issue:`57252`)

pandas/core/indexes/base.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -1374,16 +1374,19 @@ def _format_attrs(self) -> list[tuple[str_t, str_t | int | bool | None]]:
13741374
return attrs
13751375

13761376
@final
1377-
def _get_level_names(self) -> Hashable | Sequence[Hashable]:
1377+
def _get_level_names(self) -> range | Sequence[Hashable]:
13781378
"""
13791379
Return a name or list of names with None replaced by the level number.
13801380
"""
13811381
if self._is_multi:
1382-
return [
1383-
level if name is None else name for level, name in enumerate(self.names)
1384-
]
1382+
return maybe_sequence_to_range(
1383+
[
1384+
level if name is None else name
1385+
for level, name in enumerate(self.names)
1386+
]
1387+
)
13851388
else:
1386-
return 0 if self.name is None else self.name
1389+
return range(1) if self.name is None else [self.name]
13871390

13881391
@final
13891392
def _mpl_repr(self) -> np.ndarray:
@@ -1630,8 +1633,11 @@ def to_frame(
16301633
from pandas import DataFrame
16311634

16321635
if name is lib.no_default:
1633-
name = self._get_level_names()
1634-
result = DataFrame({name: self}, copy=False)
1636+
result_name = self._get_level_names()
1637+
else:
1638+
result_name = Index([name]) # type: ignore[assignment]
1639+
result = DataFrame(self, copy=False)
1640+
result.columns = result_name
16351641

16361642
if index:
16371643
result.index = self

pandas/tests/indexes/multi/test_conversion.py

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pandas import (
66
DataFrame,
77
MultiIndex,
8+
RangeIndex,
89
)
910
import pandas._testing as tm
1011

@@ -148,6 +149,13 @@ def test_to_frame_duplicate_labels():
148149
tm.assert_frame_equal(result, expected)
149150

150151

152+
def test_to_frame_column_rangeindex():
153+
mi = MultiIndex.from_arrays([[1, 2], ["a", "b"]])
154+
result = mi.to_frame().columns
155+
expected = RangeIndex(2)
156+
tm.assert_index_equal(result, expected, exact=True)
157+
158+
151159
def test_to_flat_index(idx):
152160
expected = pd.Index(
153161
(

pandas/tests/indexes/test_common.py

+14
Original file line numberDiff line numberDiff line change
@@ -508,3 +508,17 @@ def test_compare_read_only_array():
508508
idx = pd.Index(arr)
509509
result = idx > 69
510510
assert result.dtype == bool
511+
512+
513+
def test_to_frame_column_rangeindex():
514+
idx = pd.Index([1])
515+
result = idx.to_frame().columns
516+
expected = RangeIndex(1)
517+
tm.assert_index_equal(result, expected, exact=True)
518+
519+
520+
def test_to_frame_name_tuple_multiindex():
521+
idx = pd.Index([1])
522+
result = idx.to_frame(name=(1, 2))
523+
expected = pd.DataFrame([1], columns=MultiIndex.from_arrays([[1], [2]]), index=idx)
524+
tm.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)