From 8a05e3a086b75555c923dc225e9a2ce71cb54bf7 Mon Sep 17 00:00:00 2001 From: Sergey Solovev Date: Fri, 1 Dec 2017 11:42:48 +0300 Subject: [PATCH 1/3] BUG: Unwanted conversion from timedelta to float (#18493) --- doc/source/whatsnew/v0.22.0.txt | 2 +- pandas/core/internals.py | 3 ++- pandas/tests/indexing/test_timedelta.py | 12 ++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index d43d5bec7175f..f22f5a9763e54 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -151,7 +151,7 @@ Indexing - Bug in :class:`IntervalIndex` where empty and purely NA data was constructed inconsistently depending on the construction method (:issue:`18421`) - Bug in ``IntervalIndex.symmetric_difference()`` where the symmetric difference with a non-``IntervalIndex`` did not raise (:issue:`18475`) - Bug in indexing a datetimelike ``Index`` that raised ``ValueError`` instead of ``IndexError`` (:issue:`18386`). - +- Bug in ``TimeDeltaBlock._can_hold_element()`` where masked assignment of a timedelta series converts the series values to float64 (:issue:`18493`) I/O ^^^ diff --git a/pandas/core/internals.py b/pandas/core/internals.py index 4f25a19d437ca..1d1d71be16c00 100644 --- a/pandas/core/internals.py +++ b/pandas/core/internals.py @@ -1956,7 +1956,8 @@ def _can_hold_element(self, element): tipo = maybe_infer_dtype_type(element) if tipo is not None: return issubclass(tipo.type, np.timedelta64) - return isinstance(element, (timedelta, np.timedelta64)) + return is_integer(element) or isinstance( + element, (timedelta, np.timedelta64)) def fillna(self, value, **kwargs): diff --git a/pandas/tests/indexing/test_timedelta.py b/pandas/tests/indexing/test_timedelta.py index 32609362e49af..3533035520e72 100644 --- a/pandas/tests/indexing/test_timedelta.py +++ b/pandas/tests/indexing/test_timedelta.py @@ -2,6 +2,7 @@ import pandas as pd from pandas.util import testing as tm +from numpy import nan class TestTimedeltaIndexing(object): @@ -47,3 +48,14 @@ def test_string_indexing(self): expected = df.iloc[0] sliced = df.loc['0 days'] tm.assert_series_equal(sliced, expected) + + @pytest.mark.parametrize( + "value, expected", + [(None, [pd.NaT, 1, 2]), + (pd.NaT, [pd.NaT, 1, 2]), + (nan, [pd.NaT, 1, 2])]) + def test_nan(self, value, expected): + series = pd.Series([0, 1, 2], dtype='timedelta64[ns]') + series[series == series[0]] = value + expected = pd.Series([pd.NaT, 1, 2], dtype='timedelta64[ns]') + tm.assert_series_equal(series, expected) From f474b1efd7546c32ef363ddfd45f367591073f94 Mon Sep 17 00:00:00 2001 From: Sergey Solovev Date: Fri, 1 Dec 2017 17:12:41 +0300 Subject: [PATCH 2/3] fixes --- doc/source/whatsnew/v0.21.1.txt | 1 + doc/source/whatsnew/v0.22.0.txt | 2 +- pandas/tests/indexing/test_timedelta.py | 21 +++++++++++++++------ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/doc/source/whatsnew/v0.21.1.txt b/doc/source/whatsnew/v0.21.1.txt index bebfd0ab50e90..825dbc654f8d2 100644 --- a/doc/source/whatsnew/v0.21.1.txt +++ b/doc/source/whatsnew/v0.21.1.txt @@ -74,6 +74,7 @@ Indexing - Bug where a ``MultiIndex`` with more than a million records was not raising ``AttributeError`` when trying to access a missing attribute (:issue:`18165`) - Bug in :class:`IntervalIndex` constructor when a list of intervals is passed with non-default ``closed`` (:issue:`18334`) - Bug in ``Index.putmask`` when an invalid mask passed (:issue:`18368`) +- Bug in masked assignment of a ``timedelta64[ns]`` dtype ``series``, incorrectly coerced to float (:issue:`18493`) - I/O diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index f22f5a9763e54..d43d5bec7175f 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -151,7 +151,7 @@ Indexing - Bug in :class:`IntervalIndex` where empty and purely NA data was constructed inconsistently depending on the construction method (:issue:`18421`) - Bug in ``IntervalIndex.symmetric_difference()`` where the symmetric difference with a non-``IntervalIndex`` did not raise (:issue:`18475`) - Bug in indexing a datetimelike ``Index`` that raised ``ValueError`` instead of ``IndexError`` (:issue:`18386`). -- Bug in ``TimeDeltaBlock._can_hold_element()`` where masked assignment of a timedelta series converts the series values to float64 (:issue:`18493`) + I/O ^^^ diff --git a/pandas/tests/indexing/test_timedelta.py b/pandas/tests/indexing/test_timedelta.py index 3533035520e72..3ad3b771b2ab2 100644 --- a/pandas/tests/indexing/test_timedelta.py +++ b/pandas/tests/indexing/test_timedelta.py @@ -2,7 +2,7 @@ import pandas as pd from pandas.util import testing as tm -from numpy import nan +import numpy as np class TestTimedeltaIndexing(object): @@ -50,12 +50,21 @@ def test_string_indexing(self): tm.assert_series_equal(sliced, expected) @pytest.mark.parametrize( - "value, expected", - [(None, [pd.NaT, 1, 2]), - (pd.NaT, [pd.NaT, 1, 2]), - (nan, [pd.NaT, 1, 2])]) - def test_nan(self, value, expected): + "value", + [None, pd.NaT, np.nan]) + def test_masked_setitem(self, value): + # issue (#18586) series = pd.Series([0, 1, 2], dtype='timedelta64[ns]') series[series == series[0]] = value expected = pd.Series([pd.NaT, 1, 2], dtype='timedelta64[ns]') tm.assert_series_equal(series, expected) + + @pytest.mark.parametrize( + "value", + [None, pd.NaT, np.nan]) + def test_listlike_setitem(self, value): + # issue (#18586) + series = pd.Series([0, 1, 2], dtype='timedelta64[ns]') + series.iloc[0] = value + expected = pd.Series([pd.NaT, 1, 2], dtype='timedelta64[ns]') + tm.assert_series_equal(series, expected) From 492889b5ae5c7ba41183d64c548b3376e5158ce3 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sat, 2 Dec 2017 12:41:01 -0500 Subject: [PATCH 3/3] small doc changes --- doc/source/whatsnew/v0.21.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.21.1.txt b/doc/source/whatsnew/v0.21.1.txt index 825dbc654f8d2..3d4850b334ff9 100644 --- a/doc/source/whatsnew/v0.21.1.txt +++ b/doc/source/whatsnew/v0.21.1.txt @@ -74,7 +74,7 @@ Indexing - Bug where a ``MultiIndex`` with more than a million records was not raising ``AttributeError`` when trying to access a missing attribute (:issue:`18165`) - Bug in :class:`IntervalIndex` constructor when a list of intervals is passed with non-default ``closed`` (:issue:`18334`) - Bug in ``Index.putmask`` when an invalid mask passed (:issue:`18368`) -- Bug in masked assignment of a ``timedelta64[ns]`` dtype ``series``, incorrectly coerced to float (:issue:`18493`) +- Bug in masked assignment of a ``timedelta64[ns]`` dtype ``Series``, incorrectly coerced to float (:issue:`18493`) - I/O