Skip to content

Commit 9429c03

Browse files
committed
Merge pull request #2990 from jreback/timedelta_fixes
ENH: support min/max on timedelta64[ns] Series
2 parents 9a6810d + 1a70843 commit 9429c03

File tree

6 files changed

+67
-29
lines changed

6 files changed

+67
-29
lines changed

RELEASE.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ pandas 0.11.0
131131
- Support null checking on timedelta64, representing (and formatting) with NaT
132132
- Support setitem with np.nan value, converts to NaT
133133
- Support min/max ops in a Dataframe (abs not working, nor do we error on non-supported ops)
134-
- Support idxmin/idxmax/abs in a Series (but with no NaT)
134+
- Support idxmin/idxmax/abs/max/min in a Series (GH2989_, GH2982_)
135135

136136
- Bug on in-place putmasking on an ``integer`` series that needs to be converted to ``float`` (GH2746_)
137137
- Bug in argsort of ``datetime64[ns]`` Series with ``NaT`` (GH2967_)
@@ -160,6 +160,7 @@ pandas 0.11.0
160160
.. _GH2973: https://github.com/pydata/pandas/issues/2973
161161
.. _GH2967: https://github.com/pydata/pandas/issues/2967
162162
.. _GH2982: https://github.com/pydata/pandas/issues/2982
163+
.. _GH2989: https://github.com/pydata/pandas/issues/2989
163164

164165

165166
pandas 0.10.1

doc/source/timeseries.rst

+20-4
Original file line numberDiff line numberDiff line change
@@ -966,14 +966,30 @@ Some timedelta numeric like operations are supported.
966966

967967
.. ipython:: python
968968
969-
s = Series(date_range('2012-1-1', periods=3, freq='D'))
969+
td - timedelta(minutes=5,seconds=5,microseconds=5)
970+
971+
``min, max`` and the corresponding ``idxmin, idxmax`` operations are support on frames
972+
973+
.. ipython:: python
974+
970975
df = DataFrame(dict(A = s - Timestamp('20120101')-timedelta(minutes=5,seconds=5),
971976
B = s - Series(date_range('2012-1-2', periods=3, freq='D'))))
972977
df
973978
974-
# timedelta arithmetic
975-
td - timedelta(minutes=5,seconds=5,microseconds=5)
976979
977-
# min/max operations
978980
df.min()
979981
df.min(axis=1)
982+
983+
df.idxmin()
984+
df.idxmax()
985+
986+
``min, max`` operations are support on series, these return a single element ``timedelta64[ns]`` Series (this avoids
987+
having to deal with numpy timedelta64 issues). ``idxmin, idxmax`` are supported as well.
988+
989+
.. ipython:: python
990+
991+
df.min().max()
992+
df.min(axis=1).min()
993+
994+
df.min().idxmax()
995+
df.min(axis=1).idxmin()

doc/source/v0.11.0.txt

+4-5
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ Bug Fixes
258258
df = DataFrame(dict(A = s, B = td))
259259
df
260260
s - s.max()
261-
s - datetime(2011,1,1,3,5)
262-
s + timedelta(minutes=5)
263261
df['C'] = df['A'] + df['B']
264262
df
265263
df.dtypes
@@ -274,10 +272,11 @@ Bug Fixes
274272

275273
# works on lhs too
276274
s.max() - s
277-
datetime(2011,1,1,3,5) - s
278-
timedelta(minutes=5) + s
279275

280-
- Fix pretty-printing of infinite data structures, GH2978
276+
# some timedelta numeric operations are supported
277+
td - timedelta(minutes=5,seconds=5,microseconds=5)
278+
279+
- Fix pretty-printing of infinite data structures (closes GH2978_)
281280

282281

283282
See the `full release notes

pandas/core/common.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -955,10 +955,10 @@ def _possibly_cast_to_timedelta(value, coerce=True):
955955
def _possibly_cast_to_datetime(value, dtype, coerce = False):
956956
""" try to cast the array/value to a datetimelike dtype, converting float nan to iNaT """
957957

958-
if isinstance(dtype, basestring):
959-
dtype = np.dtype(dtype)
960-
961958
if dtype is not None:
959+
if isinstance(dtype, basestring):
960+
dtype = np.dtype(dtype)
961+
962962
is_datetime64 = is_datetime64_dtype(dtype)
963963
is_timedelta64 = is_timedelta64_dtype(dtype)
964964

@@ -984,21 +984,28 @@ def _possibly_cast_to_datetime(value, dtype, coerce = False):
984984
except:
985985
pass
986986

987-
elif dtype is None:
988-
# we might have a array (or single object) that is datetime like, and no dtype is passed
989-
# don't change the value unless we find a datetime set
990-
v = value
991-
if not is_list_like(v):
992-
v = [ v ]
993-
if len(v):
994-
inferred_type = lib.infer_dtype(v)
995-
if inferred_type == 'datetime':
996-
try:
997-
value = tslib.array_to_datetime(np.array(v))
998-
except:
999-
pass
1000-
elif inferred_type == 'timedelta':
1001-
value = _possibly_cast_to_timedelta(value)
987+
else:
988+
989+
# only do this if we have an array and the dtype of the array is not setup already
990+
# we are not an integer/object, so don't bother with this conversion
991+
if isinstance(value, np.ndarray) and not (issubclass(value.dtype.type, np.integer) or value.dtype == np.object_):
992+
pass
993+
994+
else:
995+
# we might have a array (or single object) that is datetime like, and no dtype is passed
996+
# don't change the value unless we find a datetime set
997+
v = value
998+
if not is_list_like(v):
999+
v = [ v ]
1000+
if len(v):
1001+
inferred_type = lib.infer_dtype(v)
1002+
if inferred_type == 'datetime':
1003+
try:
1004+
value = tslib.array_to_datetime(np.array(v))
1005+
except:
1006+
pass
1007+
elif inferred_type == 'timedelta':
1008+
value = _possibly_cast_to_timedelta(value)
10021009

10031010
return value
10041011

pandas/core/nanops.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,13 @@ def _wrap_results(result,dtype):
146146
result = result.view(dtype)
147147
elif issubclass(dtype.type, np.timedelta64):
148148
if not isinstance(result, np.ndarray):
149-
pass
149+
150+
# this is a scalar timedelta result!
151+
# we have series convert then take the element (scalar)
152+
# as series will do the right thing in py3 (and deal with numpy 1.6.2
153+
# bug in that it results dtype of timedelta64[us]
154+
from pandas import Series
155+
result = Series([result],dtype='timedelta64[ns]')
150156
else:
151157
result = result.view(dtype)
152158

pandas/tests/test_series.py

+9
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,15 @@ def test_timedelta64_functions(self):
18381838
result = (s1-s2).abs()
18391839
assert_series_equal(result,expected)
18401840

1841+
# max/min
1842+
result = td.max()
1843+
expected = Series([timedelta(2)],dtype='timedelta64[ns]')
1844+
assert_series_equal(result,expected)
1845+
1846+
result = td.min()
1847+
expected = Series([timedelta(1)],dtype='timedelta64[ns]')
1848+
assert_series_equal(result,expected)
1849+
18411850
def test_sub_of_datetime_from_TimeSeries(self):
18421851
from pandas.core import common as com
18431852
from datetime import datetime

0 commit comments

Comments
 (0)