From 78d967acf9d0b9145ae4cc70f1017b275eea1fd2 Mon Sep 17 00:00:00 2001 From: Pietro Battiston Date: Fri, 20 Oct 2017 18:37:34 +0200 Subject: [PATCH 1/2] BUG: get_level_values() on int level upcasts to Float64Index if needed closes #17924 --- doc/source/whatsnew/v0.22.0.txt | 1 + pandas/core/indexes/numeric.py | 8 ++++++++ pandas/tests/indexes/test_multi.py | 23 ++++++++++++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index 304ccd1f9350b..82e1bd2249134 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -181,6 +181,7 @@ Indexing - Bug in :func:`Series.truncate` which raises ``TypeError`` with a monotonic ``PeriodIndex`` (:issue:`17717`) - Bug in :func:`DataFrame.groupby` where tuples were interpreted as lists of keys rather than as keys (:issue:`17979`, :issue:`18249`) - Bug in :func:`MultiIndex.remove_unused_levels`` which would fill nan values (:issue:`18417`) +- Bug in :func:`MultiIndex.get_level_values` which would return an invalid index on level of ints with missing values (:issue:`17924`) - Bug in :func:`MultiIndex.from_tuples`` which would fail to take zipped tuples in python3 (:issue:`18434`) - Bug in :class:`Index`` construction from list of mixed type tuples (:issue:`18505`) - Bug in :class:`IntervalIndex` where empty and purely NA data was constructed inconsistently depending on the construction method (:issue:`18421`) diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index fddbb2de83dca..a5d437100c503 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -62,6 +62,14 @@ def _maybe_cast_slice_bound(self, label, side, kind): # we will try to coerce to integers return self._maybe_cast_indexer(label) + @Appender(_index_shared_docs['_shallow_copy']) + def _shallow_copy(self, values=None, **kwargs): + if values is not None and not self._can_hold_na: + # Ensure we are not returning an Int64Index with float data: + return self._shallow_copy_with_infer(values=values, **kwargs) + return (super(NumericIndex, self)._shallow_copy(values=values, + **kwargs)) + def _convert_for_op(self, value): """ Convert value to be insertable to ndarray """ diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index a2c0a75e21f43..e86b786e0d717 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -997,8 +997,8 @@ def test_get_level_values(self): exp = CategoricalIndex([1, 2, 3, 1, 2, 3]) tm.assert_index_equal(index.get_level_values(1), exp) - @pytest.mark.xfail(reason='GH 17924 (returns Int64Index with float data)') def test_get_level_values_int_with_na(self): + # GH 17924 arrays = [['a', 'b', 'b'], [1, np.nan, 2]] index = pd.MultiIndex.from_arrays(arrays) result = index.get_level_values(1) @@ -1024,14 +1024,27 @@ def test_get_level_values_na(self): arrays = [['a', 'b', 'b'], pd.DatetimeIndex([0, 1, pd.NaT])] index = pd.MultiIndex.from_arrays(arrays) - values = index.get_level_values(1) + result = index.get_level_values(1) expected = pd.DatetimeIndex([0, 1, pd.NaT]) - tm.assert_index_equal(values, expected) + tm.assert_index_equal(result, expected) arrays = [[], []] index = pd.MultiIndex.from_arrays(arrays) - values = index.get_level_values(0) - assert values.shape == (0, ) + result = index.get_level_values(0) + expected = pd.Index([], dtype=object) + tm.assert_index_equal(result, expected) + + def test_get_level_values_all_na(self): + # GH 17924 when level entirely consists of nan + arrays = [[np.nan, np.nan, np.nan], ['a', np.nan, 1]] + index = pd.MultiIndex.from_arrays(arrays) + result = index.get_level_values(0) + expected = pd.Index([np.nan, np.nan, np.nan], dtype=np.float64) + tm.assert_index_equal(result, expected) + + result = index.get_level_values(1) + expected = pd.Index(['a', np.nan, 1], dtype=object) + tm.assert_index_equal(result, expected) def test_reorder_levels(self): # this blows up From a8ad746d5796933203787b616fb4d9785aa8b4bb Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sun, 10 Dec 2017 13:32:49 -0500 Subject: [PATCH 2/2] clean --- pandas/core/indexes/numeric.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index a5d437100c503..72aeafbe7e1ab 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -403,9 +403,11 @@ def __contains__(self, other): try: return len(other) <= 1 and ibase._try_get_item(other) in self except TypeError: - return False - except: - return False + pass + except TypeError: + pass + + return False @Appender(_index_shared_docs['get_loc']) def get_loc(self, key, method=None, tolerance=None):