Skip to content

Commit d456442

Browse files
authored
Merge branch 'main' into np2
2 parents 4224842 + ddc3144 commit d456442

File tree

7 files changed

+71
-4
lines changed

7 files changed

+71
-4
lines changed

Diff for: doc/source/whatsnew/v3.0.0.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ Removal of prior version deprecations/changes
244244

245245
Performance improvements
246246
~~~~~~~~~~~~~~~~~~~~~~~~
247+
- :meth:`Series.str.extract` returns a :class:`RangeIndex` columns instead of an :class:`Index` column when possible (:issue:`57542`)
247248
- Performance improvement in :class:`DataFrame` when ``data`` is a ``dict`` and ``columns`` is specified (:issue:`24368`)
248249
- Performance improvement in :meth:`DataFrame.join` for sorted but non-unique indexes (:issue:`56941`)
249250
- Performance improvement in :meth:`DataFrame.join` when left and/or right are non-unique and ``how`` is ``"left"``, ``"right"``, or ``"inner"`` (:issue:`56817`)
@@ -252,11 +253,11 @@ Performance improvements
252253
- Performance improvement in :meth:`Index.join` by propagating cached attributes in cases where the result matches one of the inputs (:issue:`57023`)
253254
- Performance improvement in :meth:`Index.take` when ``indices`` is a full range indexer from zero to length of index (:issue:`56806`)
254255
- Performance improvement in :meth:`MultiIndex.equals` for equal length indexes (:issue:`56990`)
256+
- Performance improvement in :meth:`RangeIndex.__getitem__` with a boolean mask returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57588`)
255257
- Performance improvement in :meth:`RangeIndex.append` when appending the same index (:issue:`57252`)
256258
- Performance improvement in :meth:`RangeIndex.take` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57445`)
257-
- Performance improvement in indexing operations for string dtypes (:issue:`56997`)
258-
- :meth:`Series.str.extract` returns a :class:`RangeIndex` columns instead of an :class:`Index` column when possible (:issue:`?``)
259259
- Performance improvement in ``DataFrameGroupBy.__len__`` and ``SeriesGroupBy.__len__`` (:issue:`57595`)
260+
- Performance improvement in indexing operations for string dtypes (:issue:`56997`)
260261

261262
.. ---------------------------------------------------------------------------
262263
.. _whatsnew_300.bug_fixes:
@@ -324,6 +325,7 @@ MultiIndex
324325

325326
I/O
326327
^^^
328+
- Bug in :meth:`DataFrame.to_excel` when writing empty :class:`DataFrame` with :class:`MultiIndex` on both axes (:issue:`57696`)
327329
-
328330
-
329331

Diff for: pandas/core/indexes/range.py

+14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
doc,
3030
)
3131

32+
from pandas.core.dtypes.base import ExtensionDtype
3233
from pandas.core.dtypes.common import (
3334
ensure_platform_int,
3435
ensure_python_int,
@@ -42,6 +43,7 @@
4243
from pandas.core import ops
4344
import pandas.core.common as com
4445
from pandas.core.construction import extract_array
46+
from pandas.core.indexers import check_array_indexer
4547
import pandas.core.indexes.base as ibase
4648
from pandas.core.indexes.base import (
4749
Index,
@@ -1048,6 +1050,18 @@ def __getitem__(self, key):
10481050
"and integer or boolean "
10491051
"arrays are valid indices"
10501052
)
1053+
elif com.is_bool_indexer(key):
1054+
if isinstance(getattr(key, "dtype", None), ExtensionDtype):
1055+
np_key = key.to_numpy(dtype=bool, na_value=False)
1056+
else:
1057+
np_key = np.asarray(key, dtype=bool)
1058+
check_array_indexer(self._range, np_key) # type: ignore[arg-type]
1059+
# Short circuit potential _shallow_copy check
1060+
if np_key.all():
1061+
return self._simple_new(self._range, name=self.name)
1062+
elif not np_key.any():
1063+
return self._simple_new(_empty_range, name=self.name)
1064+
return self.take(np.flatnonzero(np_key))
10511065
return super().__getitem__(key)
10521066

10531067
def _getitem_slice(self, slobj: slice) -> Self:

Diff for: pandas/io/excel/_calamine.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def load_workbook(
7575
from python_calamine import load_workbook
7676

7777
return load_workbook(
78-
filepath_or_buffer, # type: ignore[arg-type]
78+
filepath_or_buffer,
7979
**engine_kwargs,
8080
)
8181

Diff for: pandas/io/formats/excel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ def _format_header_mi(self) -> Iterable[ExcelCell]:
620620
lnum = 0
621621

622622
if self.index and isinstance(self.df.index, MultiIndex):
623-
coloffset = len(self.df.index[0]) - 1
623+
coloffset = self.df.index.nlevels - 1
624624

625625
if self.merge_cells:
626626
# Format multi-index as a merged cells.

Diff for: pandas/tests/indexes/ranges/test_range.py

+38
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,41 @@ def test_append_one_nonempty_preserve_step():
623623
expected = RangeIndex(0, -1, -1)
624624
result = RangeIndex(0).append([expected])
625625
tm.assert_index_equal(result, expected, exact=True)
626+
627+
628+
def test_getitem_boolmask_all_true():
629+
ri = RangeIndex(3, name="foo")
630+
expected = ri.copy()
631+
result = ri[[True] * 3]
632+
tm.assert_index_equal(result, expected, exact=True)
633+
634+
635+
def test_getitem_boolmask_all_false():
636+
ri = RangeIndex(3, name="foo")
637+
result = ri[[False] * 3]
638+
expected = RangeIndex(0, name="foo")
639+
tm.assert_index_equal(result, expected, exact=True)
640+
641+
642+
def test_getitem_boolmask_returns_rangeindex():
643+
ri = RangeIndex(3, name="foo")
644+
result = ri[[False, True, True]]
645+
expected = RangeIndex(1, 3, name="foo")
646+
tm.assert_index_equal(result, expected, exact=True)
647+
648+
result = ri[[True, False, True]]
649+
expected = RangeIndex(0, 3, 2, name="foo")
650+
tm.assert_index_equal(result, expected, exact=True)
651+
652+
653+
def test_getitem_boolmask_returns_index():
654+
ri = RangeIndex(4, name="foo")
655+
result = ri[[True, True, False, True]]
656+
expected = Index([0, 1, 3], name="foo")
657+
tm.assert_index_equal(result, expected)
658+
659+
660+
def test_getitem_boolmask_wrong_length():
661+
ri = RangeIndex(4, name="foo")
662+
with pytest.raises(IndexError, match="Boolean index has wrong length"):
663+
ri[[True]]

Diff for: pandas/tests/io/excel/test_writers.py

+11
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,17 @@ def test_to_excel_empty_multiindex(self, tmp_excel):
936936
result, expected, check_index_type=False, check_dtype=False
937937
)
938938

939+
def test_to_excel_empty_multiindex_both_axes(self, tmp_excel):
940+
# GH 57696
941+
df = DataFrame(
942+
[],
943+
index=MultiIndex.from_tuples([], names=[0, 1]),
944+
columns=MultiIndex.from_tuples([("A", "B")]),
945+
)
946+
df.to_excel(tmp_excel)
947+
result = pd.read_excel(tmp_excel, header=[0, 1], index_col=[0, 1])
948+
tm.assert_frame_equal(result, df)
949+
939950
def test_to_excel_float_format(self, tmp_excel):
940951
df = DataFrame(
941952
[[0.123456, 0.234567, 0.567567], [12.32112, 123123.2, 321321.2]],

Diff for: pandas/tests/io/pytables/test_append.py

+2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ def test_append_series(setup_path):
132132

133133
# select on the index and values
134134
expected = ns[(ns > 70) & (ns.index < 90)]
135+
# Reading/writing RangeIndex info is not supported yet
136+
expected.index = Index(expected.index._data)
135137
result = store.select("ns", "foo>70 and index<90")
136138
tm.assert_series_equal(result, expected, check_index_type=True)
137139

0 commit comments

Comments
 (0)