Skip to content

BUG: (nan)?(arg)?(max|min) handling of NaT inconsistent #5222

@ischwabacher

Description

@ischwabacher

I would expect the handling of NaT to parallel the handling of NaN: the max or min of an array containing NaT should be NaT, and the argmax or argmin of that array should be the index of the first NaT. Instead, max and min ignore NaT as nanmax and nanmin could be expected to do, while argmax and argmin treat NaT as a minimal element. This inconsistency breaks the invariant that arr[argmin(arr)] == min(arr) (with the additional interpretation that NaN == NaN for this purpose).

To compound this, nanmax and nanmin each raise when applied to m8 or M8 arrays, and nanargmax and nanargmin have the same behavior as argmax and argmin.

In [1]: import numpy as np

In [2]: funcs = [getattr(np, ''.join([nan, arg, which]))
   ...:              for nan in ('', 'nan')
   ...:              for arg in ('', 'arg')
   ...:              for which in ('max', 'min')]

In [3]: arrays = [np.arange(0, 4, dtype=t) for t in ('f8', 'M8[ns]', 'm8[ns]')]

In [4]: for arr in arrays:
   ...:     try:
   ...:         arr[[1, 3]] = 'nan'
   ...:     except ValueError:
   ...:         arr[[1, 3]] = 'nat'
   ...:         

In [5]: for f in funcs:
   ...:     for a in arrays:
   ...:         print('{}(dtype={}) = '.format(f.__name__, a.dtype), end='')
   ...:         try:
   ...:             print(f(a))
   ...:         except Exception as e:
   ...:             print(repr(e))
   ...:             
amax(dtype=float64) = nan
amax(dtype=datetime64[ns]) = 1969-12-31T18:00:00.000000002-0600
amax(dtype=timedelta64[ns]) = 2 nanoseconds
amin(dtype=float64) = nan
amin(dtype=datetime64[ns]) = 1969-12-31T18:00:00.000000000-0600
amin(dtype=timedelta64[ns]) = 0 nanoseconds
argmax(dtype=float64) = 1
argmax(dtype=datetime64[ns]) = 2
argmax(dtype=timedelta64[ns]) = 2
argmin(dtype=float64) = 1
argmin(dtype=datetime64[ns]) = 1
argmin(dtype=timedelta64[ns]) = 1
nanmax(dtype=float64) = 2.0
nanmax(dtype=datetime64[ns]) = TypeError("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''",)
nanmax(dtype=timedelta64[ns]) = TypeError("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''",)
nanmin(dtype=float64) = 0.0
nanmin(dtype=datetime64[ns]) = TypeError("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''",)
nanmin(dtype=timedelta64[ns]) = TypeError("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''",)
nanargmax(dtype=float64) = 2
nanargmax(dtype=datetime64[ns]) = 2
nanargmax(dtype=timedelta64[ns]) = 2
nanargmin(dtype=float64) = 0
nanargmin(dtype=datetime64[ns]) = 1
nanargmin(dtype=timedelta64[ns]) = 1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions