Skip to content

Commit 0c1e052

Browse files
BUG: series resample with timedelta values looses dtype (GH13119) (#14118)
_possibly_downcast_to_dtype did not work for timedelta data
1 parent 10bf721 commit 0c1e052

File tree

4 files changed

+64
-35
lines changed

4 files changed

+64
-35
lines changed

doc/source/whatsnew/v0.19.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ Bug Fixes
12601260
- Bug in ``.value_counts`` raises ``OutOfBoundsDatetime`` if data exceeds ``datetime64[ns]`` bounds (:issue:`13663`)
12611261
- Bug in ``DatetimeIndex`` may raise ``OutOfBoundsDatetime`` if input ``np.datetime64`` has other unit than ``ns`` (:issue:`9114`)
12621262
- Bug in ``Series`` creation with ``np.datetime64`` which has other unit than ``ns`` as ``object`` dtype results in incorrect values (:issue:`13876`)
1263-
1263+
- Bug in ``resample`` with timedelta data where data was casted to float (:issue:`13119`).
12641264
- Bug in ``pd.isnull()`` ``pd.notnull()`` raise ``TypeError`` if input datetime-like has other unit than ``ns`` (:issue:`13389`)
12651265
- Bug in ``pd.merge()`` may raise ``TypeError`` if input datetime-like has other unit than ``ns`` (:issue:`13389`)
12661266

pandas/tests/types/test_cast.py

+44-32
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,56 @@
2424
_multiprocess_can_split_ = True
2525

2626

27-
def test_downcast_conv():
28-
# test downcasting
27+
class TestPossiblyDowncast(tm.TestCase):
2928

30-
arr = np.array([8.5, 8.6, 8.7, 8.8, 8.9999999999995])
31-
result = _possibly_downcast_to_dtype(arr, 'infer')
32-
assert (np.array_equal(result, arr))
29+
def test_downcast_conv(self):
30+
# test downcasting
3331

34-
arr = np.array([8., 8., 8., 8., 8.9999999999995])
35-
result = _possibly_downcast_to_dtype(arr, 'infer')
36-
expected = np.array([8, 8, 8, 8, 9])
37-
assert (np.array_equal(result, expected))
38-
39-
arr = np.array([8., 8., 8., 8., 9.0000000000005])
40-
result = _possibly_downcast_to_dtype(arr, 'infer')
41-
expected = np.array([8, 8, 8, 8, 9])
42-
assert (np.array_equal(result, expected))
43-
44-
# conversions
32+
arr = np.array([8.5, 8.6, 8.7, 8.8, 8.9999999999995])
33+
result = _possibly_downcast_to_dtype(arr, 'infer')
34+
assert (np.array_equal(result, arr))
4535

46-
expected = np.array([1, 2])
47-
for dtype in [np.float64, object, np.int64]:
48-
arr = np.array([1.0, 2.0], dtype=dtype)
36+
arr = np.array([8., 8., 8., 8., 8.9999999999995])
4937
result = _possibly_downcast_to_dtype(arr, 'infer')
50-
tm.assert_almost_equal(result, expected, check_dtype=False)
38+
expected = np.array([8, 8, 8, 8, 9])
39+
assert (np.array_equal(result, expected))
5140

52-
for dtype in [np.float64, object]:
53-
expected = np.array([1.0, 2.0, np.nan], dtype=dtype)
54-
arr = np.array([1.0, 2.0, np.nan], dtype=dtype)
41+
arr = np.array([8., 8., 8., 8., 9.0000000000005])
5542
result = _possibly_downcast_to_dtype(arr, 'infer')
56-
tm.assert_almost_equal(result, expected)
57-
58-
# empties
59-
for dtype in [np.int32, np.float64, np.float32, np.bool_,
60-
np.int64, object]:
61-
arr = np.array([], dtype=dtype)
62-
result = _possibly_downcast_to_dtype(arr, 'int64')
63-
tm.assert_almost_equal(result, np.array([], dtype=np.int64))
64-
assert result.dtype == np.int64
43+
expected = np.array([8, 8, 8, 8, 9])
44+
assert (np.array_equal(result, expected))
45+
46+
# conversions
47+
48+
expected = np.array([1, 2])
49+
for dtype in [np.float64, object, np.int64]:
50+
arr = np.array([1.0, 2.0], dtype=dtype)
51+
result = _possibly_downcast_to_dtype(arr, 'infer')
52+
tm.assert_almost_equal(result, expected, check_dtype=False)
53+
54+
for dtype in [np.float64, object]:
55+
expected = np.array([1.0, 2.0, np.nan], dtype=dtype)
56+
arr = np.array([1.0, 2.0, np.nan], dtype=dtype)
57+
result = _possibly_downcast_to_dtype(arr, 'infer')
58+
tm.assert_almost_equal(result, expected)
59+
60+
# empties
61+
for dtype in [np.int32, np.float64, np.float32, np.bool_,
62+
np.int64, object]:
63+
arr = np.array([], dtype=dtype)
64+
result = _possibly_downcast_to_dtype(arr, 'int64')
65+
tm.assert_almost_equal(result, np.array([], dtype=np.int64))
66+
assert result.dtype == np.int64
67+
68+
def test_datetimelikes_nan(self):
69+
arr = np.array([1, 2, np.nan])
70+
exp = np.array([1, 2, np.datetime64('NaT')], dtype='datetime64[ns]')
71+
res = _possibly_downcast_to_dtype(arr, 'datetime64[ns]')
72+
tm.assert_numpy_array_equal(res, exp)
73+
74+
exp = np.array([1, 2, np.timedelta64('NaT')], dtype='timedelta64[ns]')
75+
res = _possibly_downcast_to_dtype(arr, 'timedelta64[ns]')
76+
tm.assert_numpy_array_equal(res, exp)
6577

6678

6779
class TestInferDtype(tm.TestCase):

pandas/tseries/tests/test_resample.py

+17
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,23 @@ def test_resample_with_nat(self):
19351935

19361936
assert_frame_equal(frame.resample('60s').mean(), frame_3s)
19371937

1938+
def test_resample_timedelta_values(self):
1939+
# GH 13119
1940+
# check that timedelta dtype is preserved when NaT values are
1941+
# introduced by the resampling
1942+
1943+
times = timedelta_range('1 day', '4 day', freq='4D')
1944+
df = DataFrame({'time': times}, index=times)
1945+
1946+
times2 = timedelta_range('1 day', '4 day', freq='2D')
1947+
exp = Series(times2, index=times2, name='time')
1948+
exp.iloc[1] = pd.NaT
1949+
1950+
res = df.resample('2D').first()['time']
1951+
tm.assert_series_equal(res, exp)
1952+
res = df['time'].resample('2D').first()
1953+
tm.assert_series_equal(res, exp)
1954+
19381955

19391956
class TestPeriodIndex(Base, tm.TestCase):
19401957
_multiprocess_can_split_ = True

pandas/types/cast.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
is_timedelta64_dtype, is_dtype_equal,
1313
is_float_dtype, is_complex_dtype,
1414
is_integer_dtype, is_datetime_or_timedelta_dtype,
15-
is_scalar,
15+
is_bool_dtype, is_scalar,
1616
_string_dtypes,
1717
_coerce_to_dtype,
1818
_ensure_int8, _ensure_int16,
@@ -89,7 +89,7 @@ def trans(x): # noqa
8989

9090
if issubclass(dtype.type, np.floating):
9191
return result.astype(dtype)
92-
elif dtype == np.bool_ or issubclass(dtype.type, np.integer):
92+
elif is_bool_dtype(dtype) or is_integer_dtype(dtype):
9393

9494
# if we don't have any elements, just astype it
9595
if not np.prod(result.shape):

0 commit comments

Comments
 (0)