Skip to content

Commit e447c33

Browse files
committed
DOC: release note for timedelta changes
TST: skip tests on numpy < 1.7 as needed for timedeltas BUG: fixup .abs for timedeltas
1 parent 9f0094f commit e447c33

File tree

12 files changed

+102
-65
lines changed

12 files changed

+102
-65
lines changed

doc/source/release.rst

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ API Changes
6262
when detecting chained assignment, related (:issue:`5938`)
6363
- DataFrame.head(0) returns self instead of empty frame (:issue:`5846`)
6464
- ``autocorrelation_plot`` now accepts ``**kwargs``. (:issue:`5623`)
65+
- ``convert_objects`` now accepts a ``convert_timedeltas='coerce'`` argument to allow forced dtype conversion of
66+
timedeltas (:issue:`5458`,:issue:`5689`)
6567

6668
Experimental Features
6769
~~~~~~~~~~~~~~~~~~~~~
@@ -78,12 +80,13 @@ Improvements to existing features
7880
- support ``dtypes`` property on ``Series/Panel/Panel4D``
7981
- extend ``Panel.apply`` to allow arbitrary functions (rather than only ufuncs) (:issue:`1148`)
8082
allow multiple axes to be used to operate on slabs of a ``Panel``
81-
- The ``ArrayFormatter``s for ``datetime`` and ``timedelta64`` now intelligently
83+
- The ``ArrayFormatter`` for ``datetime`` and ``timedelta64`` now intelligently
8284
limit precision based on the values in the array (:issue:`3401`)
8385
- pd.show_versions() is now available for convenience when reporting issues.
8486
- perf improvements to Series.str.extract (:issue:`5944`)
8587
- perf improvments in ``dtypes/ftypes`` methods (:issue:`5968`)
8688
- perf improvments in indexing with object dtypes (:issue:`5968`)
89+
- improved dtype inference for ``timedelta`` like passed to constructors (:issue:`5458`,:issue:`5689`)
8790

8891
.. _release.bug_fixes-0.13.1:
8992

@@ -122,6 +125,7 @@ Bug Fixes
122125
- Recent changes in IPython cause warnings to be emitted when using previous versions
123126
of pandas in QTConsole, now fixed. If you're using an older version and
124127
need to supress the warnings, see (:issue:`5922`).
128+
- Bug in merging ``timedelta`` dtypes (:issue:`5695`)
125129

126130
pandas 0.13.0
127131
-------------

doc/source/v0.13.1.txt

+22-22
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
v0.13.1 (???)
44
-------------
55

6-
This is a major release from 0.13.0 and includes a number of API changes, several new features and
6+
This is a minor release from 0.13.0 and includes a number of API changes, several new features and
77
enhancements along with a large number of bug fixes.
88

99
Highlights include:
@@ -29,6 +29,27 @@ Deprecations
2929
Enhancements
3030
~~~~~~~~~~~~
3131

32+
- The ``ArrayFormatter`` for ``datetime`` and ``timedelta64`` now intelligently
33+
limit precision based on the values in the array (:issue:`3401`)
34+
35+
Previously output might look like:
36+
37+
.. code-block:: python
38+
39+
age today diff
40+
0 2001-01-01 00:00:00 2013-04-19 00:00:00 4491 days, 00:00:00
41+
1 2004-06-01 00:00:00 2013-04-19 00:00:00 3244 days, 00:00:00
42+
43+
Now the output looks like:
44+
45+
.. ipython:: python
46+
47+
df = DataFrame([ Timestamp('20010101'),
48+
Timestamp('20040601') ], columns=['age'])
49+
df['today'] = Timestamp('20130419')
50+
df['diff'] = df['today']-df['age']
51+
df
52+
3253
- ``Panel.apply`` will work on non-ufuncs. See :ref:`the docs<basics.apply_panel>`.
3354

3455
.. ipython:: python
@@ -83,27 +104,6 @@ Enhancements
83104
result
84105
result.loc[:,:,'ItemA']
85106

86-
- The ``ArrayFormatter``s for ``datetime`` and ``timedelta64`` now intelligently
87-
limit precision based on the values in the array (:issue:`3401`)
88-
89-
Previously output might look like:
90-
91-
.. code-block:: python
92-
93-
age today diff
94-
0 2001-01-01 00:00:00 2013-04-19 00:00:00 4491 days, 00:00:00
95-
1 2004-06-01 00:00:00 2013-04-19 00:00:00 3244 days, 00:00:00
96-
97-
Now the output looks like:
98-
99-
.. ipython:: python
100-
101-
df = DataFrame([ Timestamp('20010101'),
102-
Timestamp('20040601') ], columns=['age'])
103-
df['today'] = Timestamp('20130419')
104-
df['diff'] = df['today']-df['age']
105-
df
106-
107107
Experimental
108108
~~~~~~~~~~~~
109109

pandas/core/common.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ def _possibly_cast_to_datetime(value, dtype, coerce=False):
16411641
elif is_timedelta64:
16421642
from pandas.tseries.timedeltas import \
16431643
_possibly_cast_to_timedelta
1644-
value = _possibly_cast_to_timedelta(value, coerce=True)
1644+
value = _possibly_cast_to_timedelta(value, coerce='compat')
16451645
except:
16461646
pass
16471647

@@ -1672,7 +1672,7 @@ def _possibly_cast_to_datetime(value, dtype, coerce=False):
16721672
elif inferred_type in ['timedelta', 'timedelta64']:
16731673
from pandas.tseries.timedeltas import \
16741674
_possibly_cast_to_timedelta
1675-
value = _possibly_cast_to_timedelta(value)
1675+
value = _possibly_cast_to_timedelta(value, coerce='compat')
16761676

16771677
return value
16781678

pandas/core/generic.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -3177,23 +3177,22 @@ def abs(self):
31773177
-------
31783178
abs: type of caller
31793179
"""
3180-
obj = np.abs(self)
31813180

31823181
# suprimo numpy 1.6 hacking
3182+
# for timedeltas
31833183
if _np_version_under1p7:
3184+
3185+
def _convert_timedeltas(x):
3186+
if x.dtype.kind == 'm':
3187+
return np.abs(x.view('i8')).astype(x.dtype)
3188+
return np.abs(x)
3189+
31843190
if self.ndim == 1:
3185-
if obj.dtype == 'm8[us]':
3186-
obj = obj.astype('m8[ns]')
3191+
return _convert_timedeltas(self)
31873192
elif self.ndim == 2:
3188-
def f(x):
3189-
if x.dtype == 'm8[us]':
3190-
x = x.astype('m8[ns]')
3191-
return x
3193+
return self.apply(_convert_timedeltas)
31923194

3193-
if 'm8[us]' in obj.dtypes.values:
3194-
obj = obj.apply(f)
3195-
3196-
return obj
3195+
return np.abs(self)
31973196

31983197
def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None,
31993198
**kwds):

pandas/lib.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ from cpython cimport (PyDict_New, PyDict_GetItem, PyDict_SetItem,
1414
Py_INCREF, PyTuple_SET_ITEM,
1515
PyList_Check, PyFloat_Check,
1616
PyString_Check,
17-
PyBytes_Check,
17+
PyBytes_Check,
1818
PyTuple_SetItem,
1919
PyTuple_New,
2020
PyObject_SetAttrString)

pandas/src/datetime.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ cdef extern from "datetime.h":
3737
bint PyDateTime_Check(object o)
3838
bint PyDate_Check(object o)
3939
bint PyTime_Check(object o)
40+
bint PyDelta_Check(object o)
4041
object PyDateTime_FromDateAndTime(int year, int month, int day, int hour,
4142
int minute, int second, int us)
4243

pandas/src/inference.pyx

+23-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cimport util
22
from tslib import NaT
3-
3+
from datetime import datetime, timedelta
44
iNaT = util.get_nat()
55

66
_TYPE_MAP = {
@@ -141,6 +141,9 @@ cdef inline bint is_date(object o):
141141
cdef inline bint is_time(object o):
142142
return PyTime_Check(o)
143143

144+
cdef inline bint is_timedelta(object o):
145+
return PyDelta_Check(o) or util.is_timedelta64_object(o)
146+
144147
def is_bool_array(ndarray values):
145148
cdef:
146149
Py_ssize_t i, n = len(values)
@@ -296,19 +299,14 @@ def is_datetime64_array(ndarray values):
296299
return False
297300
return True
298301

299-
def is_timedelta(object o):
300-
import datetime
301-
return isinstance(o,datetime.timedelta) or isinstance(o,np.timedelta64)
302-
303302
def is_timedelta_array(ndarray values):
304-
import datetime
305303
cdef int i, n = len(values)
306304
cdef object v
307305
if n == 0:
308306
return False
309307
for i in range(n):
310308
v = values[i]
311-
if not (isinstance(v,datetime.timedelta) or is_null_datetimelike(v)):
309+
if not (PyDelta_Check(v) or is_null_datetimelike(v)):
312310
return False
313311
return True
314312

@@ -319,21 +317,19 @@ def is_timedelta64_array(ndarray values):
319317
return False
320318
for i in range(n):
321319
v = values[i]
322-
if not (isinstance(v,np.timedelta64) or is_null_datetimelike(v)):
320+
if not (util.is_timedelta64_object(v) or is_null_datetimelike(v)):
323321
return False
324322
return True
325323

326324
def is_timedelta_or_timedelta64_array(ndarray values):
327325
""" infer with timedeltas and/or nat/none """
328-
import datetime
329326
cdef int i, n = len(values)
330327
cdef object v
331328
if n == 0:
332329
return False
333330
for i in range(n):
334331
v = values[i]
335-
if not (isinstance(v,datetime.timedelta) or isinstance(v,np.timedelta64) or
336-
is_null_datetimelike(v)):
332+
if not (is_timedelta(v) or is_null_datetimelike(v)):
337333
return False
338334
return True
339335

@@ -486,10 +482,14 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=0,
486482
complexes = np.empty(n, dtype='c16')
487483
ints = np.empty(n, dtype='i8')
488484
bools = np.empty(n, dtype=np.uint8)
489-
datetimes = np.empty(n, dtype='M8[ns]')
490-
idatetimes = datetimes.view(np.int64)
491-
timedeltas = np.empty(n, dtype='m8[ns]')
492-
itimedeltas = timedeltas.view(np.int64)
485+
486+
if convert_datetime:
487+
datetimes = np.empty(n, dtype='M8[ns]')
488+
idatetimes = datetimes.view(np.int64)
489+
490+
if convert_timedelta:
491+
timedeltas = np.empty(n, dtype='m8[ns]')
492+
itimedeltas = timedeltas.view(np.int64)
493493

494494
onan = np.nan
495495
fnan = np.nan
@@ -625,8 +625,6 @@ def try_parse_dates(ndarray[object] values, parser=None,
625625
Py_ssize_t i, n
626626
ndarray[object] result
627627

628-
from datetime import datetime, timedelta
629-
630628
n = len(values)
631629
result = np.empty(n, dtype='O')
632630

@@ -884,8 +882,10 @@ def map_infer_mask(ndarray arr, object f, ndarray[uint8_t] mask,
884882
result[i] = val
885883

886884
if convert:
887-
return maybe_convert_objects(result, try_float=0,
888-
convert_datetime=0)
885+
return maybe_convert_objects(result,
886+
try_float=0,
887+
convert_datetime=0,
888+
convert_timedelta=0)
889889

890890
return result
891891

@@ -920,8 +920,10 @@ def map_infer(ndarray arr, object f, bint convert=1):
920920
result[i] = val
921921

922922
if convert:
923-
return maybe_convert_objects(result, try_float=0,
924-
convert_datetime=0)
923+
return maybe_convert_objects(result,
924+
try_float=0,
925+
convert_datetime=0,
926+
convert_timedelta=0)
925927

926928
return result
927929

pandas/tests/test_series.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -2253,8 +2253,9 @@ def test_constructor_dtype_timedelta64(self):
22532253
td = Series([timedelta(days=1)])
22542254
self.assert_(td.dtype == 'timedelta64[ns]')
22552255

2256-
td = Series([timedelta(days=1),timedelta(days=2),np.timedelta64(1,'s')])
2257-
self.assert_(td.dtype == 'timedelta64[ns]')
2256+
if not _np_version_under1p7:
2257+
td = Series([timedelta(days=1),timedelta(days=2),np.timedelta64(1,'s')])
2258+
self.assert_(td.dtype == 'timedelta64[ns]')
22582259

22592260
# mixed with NaT
22602261
from pandas import tslib
@@ -2281,8 +2282,9 @@ def test_constructor_dtype_timedelta64(self):
22812282
td = Series([pd.NaT, np.timedelta64(300000000)])
22822283
self.assert_(td.dtype == 'timedelta64[ns]')
22832284

2284-
td = Series([np.timedelta64(1,'s')])
2285-
self.assert_(td.dtype == 'timedelta64[ns]')
2285+
if not _np_version_under1p7:
2286+
td = Series([np.timedelta64(1,'s')])
2287+
self.assert_(td.dtype == 'timedelta64[ns]')
22862288

22872289
# these are frequency conversion astypes
22882290
#for t in ['s', 'D', 'us', 'ms']:
@@ -2878,6 +2880,9 @@ def test_bfill(self):
28782880
assert_series_equal(ts.bfill(), ts.fillna(method='bfill'))
28792881

28802882
def test_sub_of_datetime_from_TimeSeries(self):
2883+
if _np_version_under1p7:
2884+
raise nose.SkipTest("timedelta broken in np 1.6.1")
2885+
28812886
from pandas.tseries.timedeltas import _possibly_cast_to_timedelta
28822887
from datetime import datetime
28832888
a = Timestamp(datetime(1993, 0o1, 0o7, 13, 30, 00))

pandas/tools/tests/test_merge.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import random
1010

1111
from pandas.compat import range, lrange, lzip, zip
12-
from pandas import compat
12+
from pandas import compat, _np_version_under1p7
1313
from pandas.tseries.index import DatetimeIndex
1414
from pandas.tools.merge import merge, concat, ordered_merge, MergeError
1515
from pandas.util.testing import (assert_frame_equal, assert_series_equal,
@@ -791,8 +791,16 @@ def test_append_dtype_coerce(self):
791791
result = df1.append(df2,ignore_index=True)
792792
assert_frame_equal(result, expected)
793793

794-
# timedelta64
794+
def test_join_append_timedeltas(self):
795+
796+
import datetime as dt
797+
from pandas import NaT
798+
799+
# timedelta64 issues with join/merge
795800
# GH 5695
801+
if _np_version_under1p7:
802+
raise nose.SkipTest("numpy < 1.7")
803+
796804
d = {'d': dt.datetime(2013, 11, 5, 5, 56), 't': dt.timedelta(0, 22500)}
797805
df = DataFrame(columns=list('dt'))
798806
df = df.append(d, ignore_index=True)
@@ -1787,6 +1795,11 @@ def test_concat_datetime64_block(self):
17871795
self.assert_((result.iloc[10:]['time'] == rng).all())
17881796

17891797
def test_concat_timedelta64_block(self):
1798+
1799+
# not friendly for < 1.7
1800+
if _np_version_under1p7:
1801+
raise nose.SkipTest("numpy < 1.7")
1802+
17901803
from pandas import to_timedelta
17911804

17921805
rng = to_timedelta(np.arange(10),unit='s')

pandas/tseries/tests/test_timedeltas.py

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def conv(v):
174174
self.assert_(result == expected)
175175

176176
def test_to_timedelta_via_apply(self):
177+
_skip_if_numpy_not_friendly()
177178

178179
# GH 5458
179180
expected = Series([np.timedelta64(1,'s')])

pandas/tseries/timedeltas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def convert(td, dtype):
163163
td *= 1000
164164
return td
165165

166-
if td == tslib.compat_NaT:
166+
if isnull(td) or td == tslib.compat_NaT or td == tslib.iNaT:
167167
return tslib.iNaT
168168

169169
# convert td value to a nanosecond value

test.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import numpy as np
2+
import pandas
3+
from pandas import Series,DataFrame
4+
5+
print pandas.__version__
6+
7+
s = Series(np.arange(1028.))
8+
9+
df = DataFrame({ i:s for i in range(1028) })
10+
11+
import pdb; pdb.set_trace()
12+
df.apply(lambda x: np.corrcoef(x,s)[0,1])

0 commit comments

Comments
 (0)