Skip to content

Commit 7b59ebf

Browse files
committed
Merge pull request #7279 from sinhrks/minmax
BUG: Index.min and max doesnt handle nan and NaT properly
2 parents df2fb49 + d623462 commit 7b59ebf

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

doc/source/v0.14.1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ There are no experimental changes in 0.14.1
6565
Bug Fixes
6666
~~~~~~~~~
6767

68+
- Bug in ``Index.min`` and ``max`` doesn't handle ``nan`` and ``NaT`` properly (:issue:`7261`)

pandas/core/base.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,13 @@ def _wrap_access_object(self, obj):
236236

237237
def max(self):
238238
""" The maximum value of the object """
239-
return self.values.max()
239+
import pandas.core.nanops
240+
return pandas.core.nanops.nanmax(self.values)
240241

241242
def min(self):
242243
""" The minimum value of the object """
243-
return self.values.min()
244+
import pandas.core.nanops
245+
return pandas.core.nanops.nanmin(self.values)
244246

245247
def value_counts(self, normalize=False, sort=True, ascending=False,
246248
bins=None):

pandas/tests/test_base.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from datetime import timedelta
2+
from datetime import datetime, timedelta
33
import numpy as np
44
import pandas.compat as compat
55
import pandas as pd
@@ -210,6 +210,39 @@ def test_ops(self):
210210
expected = expected.astype('M8[ns]').astype('int64')
211211
self.assertEqual(result.value, expected)
212212

213+
def test_nanops(self):
214+
# GH 7261
215+
for op in ['max','min']:
216+
for klass in [Index, Series]:
217+
218+
obj = klass([np.nan, 2.0])
219+
self.assertEqual(getattr(obj, op)(), 2.0)
220+
221+
obj = klass([np.nan])
222+
self.assertTrue(pd.isnull(getattr(obj, op)()))
223+
224+
obj = klass([])
225+
self.assertTrue(pd.isnull(getattr(obj, op)()))
226+
227+
obj = klass([pd.NaT, datetime(2011, 11, 1)])
228+
# check DatetimeIndex monotonic path
229+
self.assertEqual(getattr(obj, op)(), datetime(2011, 11, 1))
230+
231+
obj = klass([pd.NaT, datetime(2011, 11, 1), pd.NaT])
232+
# check DatetimeIndex non-monotonic path
233+
self.assertEqual(getattr(obj, op)(), datetime(2011, 11, 1))
234+
235+
# explicitly create DatetimeIndex
236+
obj = DatetimeIndex([])
237+
self.assertTrue(pd.isnull(getattr(obj, op)()))
238+
239+
obj = DatetimeIndex([pd.NaT])
240+
self.assertTrue(pd.isnull(getattr(obj, op)()))
241+
242+
obj = DatetimeIndex([pd.NaT, pd.NaT, pd.NaT])
243+
self.assertTrue(pd.isnull(getattr(obj, op)()))
244+
245+
213246
def test_value_counts_unique_nunique(self):
214247
for o in self.objs:
215248
klass = type(o)

pandas/tseries/index.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -1758,20 +1758,28 @@ def min(self, axis=None):
17581758
"""
17591759
Overridden ndarray.min to return a Timestamp
17601760
"""
1761-
if self.is_monotonic:
1762-
return self[0]
1761+
mask = self.asi8 == tslib.iNaT
1762+
masked = self[~mask]
1763+
if len(masked) == 0:
1764+
return tslib.NaT
1765+
elif self.is_monotonic:
1766+
return masked[0]
17631767
else:
1764-
min_stamp = self.asi8.min()
1768+
min_stamp = masked.asi8.min()
17651769
return Timestamp(min_stamp, tz=self.tz)
17661770

17671771
def max(self, axis=None):
17681772
"""
17691773
Overridden ndarray.max to return a Timestamp
17701774
"""
1771-
if self.is_monotonic:
1772-
return self[-1]
1775+
mask = self.asi8 == tslib.iNaT
1776+
masked = self[~mask]
1777+
if len(masked) == 0:
1778+
return tslib.NaT
1779+
elif self.is_monotonic:
1780+
return masked[-1]
17731781
else:
1774-
max_stamp = self.asi8.max()
1782+
max_stamp = masked.asi8.max()
17751783
return Timestamp(max_stamp, tz=self.tz)
17761784

17771785
def to_julian_date(self):

0 commit comments

Comments
 (0)