Skip to content

REF: share Datetimelike argmin/min etc with Index #42150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 25, 2021
81 changes: 81 additions & 0 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6058,6 +6058,9 @@ def __inv__(self):
# TODO: __inv__ vs __invert__?
return self._unary_method(lambda x: -x)

# --------------------------------------------------------------------
# Reductions

def any(self, *args, **kwargs):
"""
Return whether any element is Truthy.
Expand Down Expand Up @@ -6178,6 +6181,84 @@ def _maybe_disable_logical_methods(self, opname: str_t):
# This call will raise
make_invalid_op(opname)(self)

@Appender(IndexOpsMixin.argmin.__doc__)
def argmin(self, axis=None, skipna=True, *args, **kwargs):
nv.validate_argmin(args, kwargs)
nv.validate_minmax_axis(axis)

if not self._is_multi and self.hasnans:
# Take advantage of cache
mask = self._isnan
if not skipna or mask.all():
return -1
return super().argmin(skipna=skipna)

@Appender(IndexOpsMixin.argmax.__doc__)
def argmax(self, axis=None, skipna=True, *args, **kwargs):
nv.validate_argmax(args, kwargs)
nv.validate_minmax_axis(axis)

if not self._is_multi and self.hasnans:
# Take advantage of cache
mask = self._isnan
if not skipna or mask.all():
return -1
return super().argmax(skipna=skipna)

@doc(IndexOpsMixin.min)
def min(self, axis=None, skipna=True, *args, **kwargs):
nv.validate_min(args, kwargs)
nv.validate_minmax_axis(axis)

if not len(self):
return self._na_value

if len(self) and self.is_monotonic_increasing:
# quick check
first = self[0]
if not isna(first):
return first

if not self._is_multi and self.hasnans:
# Take advantage of cache
mask = self._isnan
if not skipna or mask.all():
return self._na_value

if not self._is_multi and not isinstance(self._values, np.ndarray):
# "ExtensionArray" has no attribute "min"
return self._values.min(skipna=skipna) # type: ignore[attr-defined]

return super().min(skipna=skipna)

@doc(IndexOpsMixin.max)
def max(self, axis=None, skipna=True, *args, **kwargs):
nv.validate_max(args, kwargs)
nv.validate_minmax_axis(axis)

if not len(self):
return self._na_value

if len(self) and self.is_monotonic_increasing:
# quick check
last = self[-1]
if not isna(last):
return last

if not self._is_multi and self.hasnans:
# Take advantage of cache
mask = self._isnan
if not skipna or mask.all():
return self._na_value

if not self._is_multi and not isinstance(self._values, np.ndarray):
# "ExtensionArray" has no attribute "max"
return self._values.max(skipna=skipna) # type: ignore[attr-defined]

return super().max(skipna=skipna)

# --------------------------------------------------------------------

@final
@property
def shape(self) -> Shape:
Expand Down
115 changes: 0 additions & 115 deletions pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from pandas._libs import (
NaT,
Timedelta,
iNaT,
lib,
)
from pandas._libs.tslibs import (
Expand Down Expand Up @@ -199,120 +198,6 @@ def tolist(self) -> list:
"""
return list(self.astype(object))

def min(self, axis=None, skipna=True, *args, **kwargs):
"""
Return the minimum value of the Index or minimum along
an axis.

See Also
--------
numpy.ndarray.min
Series.min : Return the minimum value in a Series.
"""
nv.validate_min(args, kwargs)
nv.validate_minmax_axis(axis)

if not len(self):
return self._na_value

i8 = self.asi8

if len(i8) and self.is_monotonic_increasing:
# quick check
if i8[0] != iNaT:
return self._data._box_func(i8[0])

if self.hasnans:
if not skipna:
return self._na_value
i8 = i8[~self._isnan]

if not len(i8):
return self._na_value

min_stamp = i8.min()
return self._data._box_func(min_stamp)

def argmin(self, axis=None, skipna=True, *args, **kwargs):
"""
Returns the indices of the minimum values along an axis.

See `numpy.ndarray.argmin` for more information on the
`axis` parameter.

See Also
--------
numpy.ndarray.argmin
"""
nv.validate_argmin(args, kwargs)
nv.validate_minmax_axis(axis)

i8 = self.asi8
if self.hasnans:
mask = self._isnan
if mask.all() or not skipna:
return -1
i8 = i8.copy()
i8[mask] = np.iinfo("int64").max
return i8.argmin()

def max(self, axis=None, skipna=True, *args, **kwargs):
"""
Return the maximum value of the Index or maximum along
an axis.

See Also
--------
numpy.ndarray.max
Series.max : Return the maximum value in a Series.
"""
nv.validate_max(args, kwargs)
nv.validate_minmax_axis(axis)

if not len(self):
return self._na_value

i8 = self.asi8

if len(i8) and self.is_monotonic:
# quick check
if i8[-1] != iNaT:
return self._data._box_func(i8[-1])

if self.hasnans:
if not skipna:
return self._na_value
i8 = i8[~self._isnan]

if not len(i8):
return self._na_value

max_stamp = i8.max()
return self._data._box_func(max_stamp)

def argmax(self, axis=None, skipna=True, *args, **kwargs):
"""
Returns the indices of the maximum values along an axis.

See `numpy.ndarray.argmax` for more information on the
`axis` parameter.

See Also
--------
numpy.ndarray.argmax
"""
nv.validate_argmax(args, kwargs)
nv.validate_minmax_axis(axis)

i8 = self.asi8
if self.hasnans:
mask = self._isnan
if mask.all() or not skipna:
return -1
i8 = i8.copy()
i8[mask] = 0
return i8.argmax()

# --------------------------------------------------------------------
# Rendering Methods

Expand Down