Skip to content

ENH: support min/max on timedelta64[ns] Series #2990

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 2 commits into from
Mar 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pandas 0.11.0
- Support null checking on timedelta64, representing (and formatting) with NaT
- Support setitem with np.nan value, converts to NaT
- Support min/max ops in a Dataframe (abs not working, nor do we error on non-supported ops)
- Support idxmin/idxmax/abs in a Series (but with no NaT)
- Support idxmin/idxmax/abs/max/min in a Series (GH2989_, GH2982_)

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


pandas 0.10.1
Expand Down
24 changes: 20 additions & 4 deletions doc/source/timeseries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -966,14 +966,30 @@ Some timedelta numeric like operations are supported.

.. ipython:: python

s = Series(date_range('2012-1-1', periods=3, freq='D'))
td - timedelta(minutes=5,seconds=5,microseconds=5)

``min, max`` and the corresponding ``idxmin, idxmax`` operations are support on frames

.. ipython:: python

df = DataFrame(dict(A = s - Timestamp('20120101')-timedelta(minutes=5,seconds=5),
B = s - Series(date_range('2012-1-2', periods=3, freq='D'))))
df

# timedelta arithmetic
td - timedelta(minutes=5,seconds=5,microseconds=5)

# min/max operations
df.min()
df.min(axis=1)

df.idxmin()
df.idxmax()

``min, max`` operations are support on series, these return a single element ``timedelta64[ns]`` Series (this avoids
having to deal with numpy timedelta64 issues). ``idxmin, idxmax`` are supported as well.

.. ipython:: python

df.min().max()
df.min(axis=1).min()

df.min().idxmax()
df.min(axis=1).idxmin()
9 changes: 4 additions & 5 deletions doc/source/v0.11.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,6 @@ Bug Fixes
df = DataFrame(dict(A = s, B = td))
df
s - s.max()
s - datetime(2011,1,1,3,5)
s + timedelta(minutes=5)
df['C'] = df['A'] + df['B']
df
df.dtypes
Expand All @@ -274,10 +272,11 @@ Bug Fixes

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

- Fix pretty-printing of infinite data structures, GH2978
# some timedelta numeric operations are supported
td - timedelta(minutes=5,seconds=5,microseconds=5)

- Fix pretty-printing of infinite data structures (closes GH2978_)


See the `full release notes
Expand Down
43 changes: 25 additions & 18 deletions pandas/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,10 +955,10 @@ def _possibly_cast_to_timedelta(value, coerce=True):
def _possibly_cast_to_datetime(value, dtype, coerce = False):
""" try to cast the array/value to a datetimelike dtype, converting float nan to iNaT """

if isinstance(dtype, basestring):
dtype = np.dtype(dtype)

if dtype is not None:
if isinstance(dtype, basestring):
dtype = np.dtype(dtype)

is_datetime64 = is_datetime64_dtype(dtype)
is_timedelta64 = is_timedelta64_dtype(dtype)

Expand All @@ -984,21 +984,28 @@ def _possibly_cast_to_datetime(value, dtype, coerce = False):
except:
pass

elif dtype is None:
# we might have a array (or single object) that is datetime like, and no dtype is passed
# don't change the value unless we find a datetime set
v = value
if not is_list_like(v):
v = [ v ]
if len(v):
inferred_type = lib.infer_dtype(v)
if inferred_type == 'datetime':
try:
value = tslib.array_to_datetime(np.array(v))
except:
pass
elif inferred_type == 'timedelta':
value = _possibly_cast_to_timedelta(value)
else:

# only do this if we have an array and the dtype of the array is not setup already
# we are not an integer/object, so don't bother with this conversion
if isinstance(value, np.ndarray) and not (issubclass(value.dtype.type, np.integer) or value.dtype == np.object_):
pass

else:
# we might have a array (or single object) that is datetime like, and no dtype is passed
# don't change the value unless we find a datetime set
v = value
if not is_list_like(v):
v = [ v ]
if len(v):
inferred_type = lib.infer_dtype(v)
if inferred_type == 'datetime':
try:
value = tslib.array_to_datetime(np.array(v))
except:
pass
elif inferred_type == 'timedelta':
value = _possibly_cast_to_timedelta(value)

return value

Expand Down
8 changes: 7 additions & 1 deletion pandas/core/nanops.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,13 @@ def _wrap_results(result,dtype):
result = result.view(dtype)
elif issubclass(dtype.type, np.timedelta64):
if not isinstance(result, np.ndarray):
pass

# this is a scalar timedelta result!
# we have series convert then take the element (scalar)
# as series will do the right thing in py3 (and deal with numpy 1.6.2
# bug in that it results dtype of timedelta64[us]
from pandas import Series
result = Series([result],dtype='timedelta64[ns]')
else:
result = result.view(dtype)

Expand Down
9 changes: 9 additions & 0 deletions pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,15 @@ def test_timedelta64_functions(self):
result = (s1-s2).abs()
assert_series_equal(result,expected)

# max/min
result = td.max()
expected = Series([timedelta(2)],dtype='timedelta64[ns]')
assert_series_equal(result,expected)

result = td.min()
expected = Series([timedelta(1)],dtype='timedelta64[ns]')
assert_series_equal(result,expected)

def test_sub_of_datetime_from_TimeSeries(self):
from pandas.core import common as com
from datetime import datetime
Expand Down