From e010e9971f78e1a302001b73052b9e2aa3ae15a3 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 2 Nov 2018 14:23:29 -0400 Subject: [PATCH 1/2] BUG: Avoid casting to double type unnecessarily when setting values in time delta column --- pandas/core/internals/blocks.py | 4 ++-- pandas/tests/indexing/test_timedelta.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 5ce8a9103f008..e84953f3dab56 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -2104,9 +2104,9 @@ def _box_func(self): def _can_hold_element(self, element): tipo = maybe_infer_dtype_type(element) if tipo is not None: - return issubclass(tipo.type, np.timedelta64) + return issubclass(tipo.type, (np.timedelta64, np.int64)) return is_integer(element) or isinstance( - element, (timedelta, np.timedelta64)) + element, (timedelta, np.timedelta64, np.int64)) def fillna(self, value, **kwargs): diff --git a/pandas/tests/indexing/test_timedelta.py b/pandas/tests/indexing/test_timedelta.py index 29031c908bda4..8d5153191ed7a 100644 --- a/pandas/tests/indexing/test_timedelta.py +++ b/pandas/tests/indexing/test_timedelta.py @@ -80,3 +80,16 @@ def test_numpy_timedelta_scalar_indexing(self, start, stop, result = s.loc[slice(start, stop)] expected = s.iloc[expected_slice] tm.assert_series_equal(result, expected) + + def test_set_dataframe_column_by_index(self): + + dt1 = pd.Timedelta(0) + dt2 = pd.Timedelta(28767471428571405) + + df = pd.DataFrame({'dt': pd.Series([dt1, dt2])}) + s = pd.Series([dt1]) + value_before = df['dt'].iloc[1].value + df.loc[[True, False]] = s + value_after = df['dt'].iloc[1].value + + assert value_before == value_after From 62ab35462b328fb294ba8be7de006e80bf53dd3d Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 5 Nov 2018 10:44:38 -0500 Subject: [PATCH 2/2] Address comments --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/tests/indexing/test_timedelta.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index fa748cccc0d65..7afe24880eadc 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1210,6 +1210,7 @@ Indexing - :class:`Index` no longer mangles ``None``, ``NaN`` and ``NaT``, i.e. they are treated as three different keys. However, for numeric Index all three are still coerced to a ``NaN`` (:issue:`22332`) - Bug in `scalar in Index` if scalar is a float while the ``Index`` is of integer dtype (:issue:`22085`) - Bug in `MultiIndex.set_levels` when levels value is not subscriptable (:issue:`23273`) +- Bug where setting a timedelta column by ``Index`` causes it to be casted to double, and therefore lose precision (:issue:`23511`) Missing ^^^^^^^ diff --git a/pandas/tests/indexing/test_timedelta.py b/pandas/tests/indexing/test_timedelta.py index 8d5153191ed7a..acd8bee3e5663 100644 --- a/pandas/tests/indexing/test_timedelta.py +++ b/pandas/tests/indexing/test_timedelta.py @@ -81,15 +81,17 @@ def test_numpy_timedelta_scalar_indexing(self, start, stop, expected = s.iloc[expected_slice] tm.assert_series_equal(result, expected) - def test_set_dataframe_column_by_index(self): - + def test_roundtrip_thru_setitem(self): + # PR 23462 dt1 = pd.Timedelta(0) dt2 = pd.Timedelta(28767471428571405) - df = pd.DataFrame({'dt': pd.Series([dt1, dt2])}) + df_copy = df.copy() s = pd.Series([dt1]) - value_before = df['dt'].iloc[1].value + + expected = df['dt'].iloc[1].value df.loc[[True, False]] = s - value_after = df['dt'].iloc[1].value + result = df['dt'].iloc[1].value - assert value_before == value_after + assert expected == result + tm.assert_frame_equal(df, df_copy)