Skip to content

Commit d79910c

Browse files
authored
PERF: RangeIndex.argmin/argmax (#57823)
1 parent 97c31a6 commit d79910c

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

doc/source/whatsnew/v3.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ Performance improvements
274274
- Performance improvement in :meth:`MultiIndex.equals` for equal length indexes (:issue:`56990`)
275275
- 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`)
276276
- Performance improvement in :meth:`RangeIndex.append` when appending the same index (:issue:`57252`)
277+
- Performance improvement in :meth:`RangeIndex.argmin` and :meth:`RangeIndex.argmax` (:issue:`57823`)
277278
- Performance improvement in :meth:`RangeIndex.round` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57824`)
278279
- Performance improvement in :meth:`RangeIndex.join` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57651`, :issue:`57752`)
279280
- Performance improvement in :meth:`RangeIndex.reindex` returning a :class:`RangeIndex` instead of a :class:`Index` when possible. (:issue:`57647`, :issue:`57752`)

pandas/core/indexes/range.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ def copy(self, name: Hashable | None = None, deep: bool = False) -> Self:
515515
new_index = self._rename(name=name)
516516
return new_index
517517

518-
def _minmax(self, meth: str) -> int | float:
518+
def _minmax(self, meth: Literal["min", "max"]) -> int | float:
519519
no_steps = len(self) - 1
520520
if no_steps == -1:
521521
return np.nan
@@ -536,6 +536,39 @@ def max(self, axis=None, skipna: bool = True, *args, **kwargs) -> int | float:
536536
nv.validate_max(args, kwargs)
537537
return self._minmax("max")
538538

539+
def _argminmax(
540+
self,
541+
meth: Literal["min", "max"],
542+
axis=None,
543+
skipna: bool = True,
544+
) -> int:
545+
nv.validate_minmax_axis(axis)
546+
if len(self) == 0:
547+
return getattr(super(), f"arg{meth}")(
548+
axis=axis,
549+
skipna=skipna,
550+
)
551+
elif meth == "min":
552+
if self.step > 0:
553+
return 0
554+
else:
555+
return len(self) - 1
556+
elif meth == "max":
557+
if self.step > 0:
558+
return len(self) - 1
559+
else:
560+
return 0
561+
else:
562+
raise ValueError(f"{meth=} must be max or min")
563+
564+
def argmin(self, axis=None, skipna: bool = True, *args, **kwargs) -> int:
565+
nv.validate_argmin(args, kwargs)
566+
return self._argminmax("min", axis=axis, skipna=skipna)
567+
568+
def argmax(self, axis=None, skipna: bool = True, *args, **kwargs) -> int:
569+
nv.validate_argmax(args, kwargs)
570+
return self._argminmax("max", axis=axis, skipna=skipna)
571+
539572
def argsort(self, *args, **kwargs) -> npt.NDArray[np.intp]:
540573
"""
541574
Returns the indices that would sort the index and its

pandas/tests/indexes/ranges/test_range.py

+24
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,30 @@ def test_getitem_boolmask_wrong_length():
763763
ri[[True]]
764764

765765

766+
@pytest.mark.parametrize(
767+
"rng",
768+
[
769+
range(0, 5, 1),
770+
range(0, 5, 2),
771+
range(10, 15, 1),
772+
range(10, 5, -1),
773+
range(10, 5, -2),
774+
range(5, 0, -1),
775+
],
776+
)
777+
@pytest.mark.parametrize("meth", ["argmax", "argmin"])
778+
def test_arg_min_max(rng, meth):
779+
ri = RangeIndex(rng)
780+
idx = Index(list(rng))
781+
assert getattr(ri, meth)() == getattr(idx, meth)()
782+
783+
784+
@pytest.mark.parametrize("meth", ["argmin", "argmax"])
785+
def test_empty_argmin_argmax_raises(meth):
786+
with pytest.raises(ValueError, match=f"attempt to get {meth} of an empty sequence"):
787+
getattr(RangeIndex(0), meth)()
788+
789+
766790
def test_getitem_integers_return_rangeindex():
767791
result = RangeIndex(0, 10, 2, name="foo")[[0, -1]]
768792
expected = RangeIndex(start=0, stop=16, step=8, name="foo")

0 commit comments

Comments
 (0)