diff --git a/RELEASE.rst b/RELEASE.rst index e73d48fb59cd2..1079fc42aa5c2 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -120,7 +120,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 in a Series (but with no NaT) + - Support idxmin/idxmax/abs in a Series (but with no NaT) - Bug on in-place putmasking on an ``integer`` series that needs to be converted to ``float`` (GH2746_) diff --git a/pandas/core/common.py b/pandas/core/common.py index 3cac5158d31ef..347cfeec26b5b 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -916,7 +916,7 @@ def _possibly_convert_platform(values): return values -def _possibly_cast_to_timedelta(value): +def _possibly_cast_to_timedelta(value, coerce=True): """ try to cast to timedelta64 w/o coercion """ # deal with numpy not being able to handle certain timedelta operations @@ -925,9 +925,12 @@ def _possibly_cast_to_timedelta(value): value = value.astype('timedelta64[ns]') return value - new_value = tslib.array_to_timedelta64(value.astype(object), coerce=False) - if new_value.dtype == 'i8': - value = np.array(new_value,dtype='timedelta64[ns]') + # we don't have a timedelta, but we want to try to convert to one (but don't force it) + if coerce: + new_value = tslib.array_to_timedelta64(value.astype(object), coerce=False) + if new_value.dtype == 'i8': + value = np.array(new_value,dtype='timedelta64[ns]') + return value def _possibly_cast_to_datetime(value, dtype, coerce = False): diff --git a/pandas/core/series.py b/pandas/core/series.py index 726216dde2269..0f3ec5120a0cd 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -711,6 +711,19 @@ def mask(self, cond): """ return self.where(~cond, nan) + def abs(self): + """ + Return an object with absolute value taken. Only applicable to objects + that are all numeric + + Returns + ------- + abs: type of caller + """ + obj = np.abs(self) + obj = com._possibly_cast_to_timedelta(obj, coerce=False) + return obj + def __setitem__(self, key, value): try: try: diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 9329bb1da2b07..bb868d2525ee1 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -2913,10 +2913,11 @@ def test_operators_timedelta64(self): self.assert_((result == diffs['A']).all() == True) # abs ###### THIS IS BROKEN NOW ###### (results are dtype=timedelta64[us] - result = np.abs(df['A']-df['B']) - result = diffs.abs() - expected = DataFrame(dict(A = df['A']-df['C'], - B = df['B']-df['A'])) + # even though fixed in series + #result = np.abs(df['A']-df['B']) + #result = diffs.abs() + #expected = DataFrame(dict(A = df['A']-df['C'], + # B = df['B']-df['A'])) #assert_frame_equal(result,expected) # mixed frame diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 28572e2eae015..66e9cc2f4931a 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -1786,9 +1786,11 @@ def test_operators_timedelta64(self): self.assert_(result.dtype=='m8[ns]') assert_series_equal(result,expected) + def test_timedelta64_functions(self): from datetime import timedelta + from pandas import date_range # index min/max td = Series(date_range('2012-1-1', periods=3, freq='D'))-Timestamp('20120101') @@ -1808,6 +1810,18 @@ def test_timedelta64_functions(self): #result = td.idxmax() #self.assert_(result == 2) + # abs + s1 = Series(date_range('20120101',periods=3)) + s2 = Series(date_range('20120102',periods=3)) + expected = Series(s2-s1) + + # this fails as numpy returns timedelta64[us] + #result = np.abs(s1-s2) + #assert_frame_equal(result,expected) + + result = (s1-s2).abs() + assert_series_equal(result,expected) + def test_sub_of_datetime_from_TimeSeries(self): from pandas.core import common as com from datetime import datetime