Skip to content

Commit 6fe6775

Browse files
committed
BUG: get_level_values() on int level upcasts to Float64Index if needed
closes pandas-dev#17924
1 parent 6e56195 commit 6fe6775

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

doc/source/whatsnew/v0.21.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,7 @@ Indexing
10611061
- Fixes ``DataFrame.loc`` for setting with alignment and tz-aware ``DatetimeIndex`` (:issue:`16889`)
10621062
- Avoids ``IndexError`` when passing an Index or Series to ``.iloc`` with older numpy (:issue:`17193`)
10631063
- Allow unicode empty strings as placeholders in multilevel columns in Python 2 (:issue:`17099`)
1064+
- Bug in :meth:`MultiIndex.get_level_values` which would return an invalid index on level of ints with missing values (:issue:`17924`)
10641065
- Bug in ``.iloc`` when used with inplace addition or assignment and an int indexer on a ``MultiIndex`` causing the wrong indexes to be read from and written to (:issue:`17148`)
10651066
- Bug in ``.isin()`` in which checking membership in empty ``Series`` objects raised an error (:issue:`16991`)
10661067
- Bug in ``CategoricalIndex`` reindexing in which specified indices containing duplicates were not being respected (:issue:`17323`)

pandas/core/indexes/numeric.py

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
is_bool_dtype,
1212
is_scalar)
1313
from pandas.core.common import _asarray_tuplesafe, _values_from_object
14+
from pandas.core.dtypes.missing import isna
1415

1516
from pandas import compat
1617
from pandas.core import algorithms
@@ -62,6 +63,17 @@ def _maybe_cast_slice_bound(self, label, side, kind):
6263
# we will try to coerce to integers
6364
return self._maybe_cast_indexer(label)
6465

66+
@Appender(_index_shared_docs['_shallow_copy'])
67+
def _shallow_copy(self, values=None, **kwargs):
68+
if values is not None and (not self._can_hold_na
69+
and not is_integer_dtype(values)
70+
and isna(values).any()):
71+
attributes = self._get_attributes_dict()
72+
attributes.update(kwargs)
73+
return Float64Index._simple_new(values, **attributes)
74+
return (super(NumericIndex, self)._shallow_copy(values=values,
75+
**kwargs))
76+
6577
def _convert_for_op(self, value):
6678
""" Convert value to be insertable to ndarray """
6779

pandas/tests/indexes/test_multi.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,8 @@ def test_get_level_values(self):
997997
exp = CategoricalIndex([1, 2, 3, 1, 2, 3])
998998
tm.assert_index_equal(index.get_level_values(1), exp)
999999

1000-
@pytest.mark.xfail(reason='GH 17924 (returns Int64Index with float data)')
10011000
def test_get_level_values_int_with_na(self):
1001+
# GH 17924
10021002
arrays = [['a', 'b', 'b'], [1, np.nan, 2]]
10031003
index = pd.MultiIndex.from_arrays(arrays)
10041004
result = index.get_level_values(1)
@@ -1024,14 +1024,26 @@ def test_get_level_values_na(self):
10241024

10251025
arrays = [['a', 'b', 'b'], pd.DatetimeIndex([0, 1, pd.NaT])]
10261026
index = pd.MultiIndex.from_arrays(arrays)
1027-
values = index.get_level_values(1)
1027+
result = index.get_level_values(1)
10281028
expected = pd.DatetimeIndex([0, 1, pd.NaT])
1029-
tm.assert_index_equal(values, expected)
1029+
tm.assert_index_equal(result, expected)
10301030

10311031
arrays = [[], []]
10321032
index = pd.MultiIndex.from_arrays(arrays)
1033-
values = index.get_level_values(0)
1034-
assert values.shape == (0, )
1033+
result = index.get_level_values(0)
1034+
expected = pd.Index([], dtype=object)
1035+
tm.assert_index_equal(result, expected)
1036+
1037+
def test_get_level_values_all_na(self):
1038+
arrays = [[np.nan, np.nan, np.nan], ['a', np.nan, 1]]
1039+
index = pd.MultiIndex.from_arrays(arrays)
1040+
result = index.get_level_values(0)
1041+
expected = pd.Index([np.nan, np.nan, np.nan], dtype=np.float64)
1042+
tm.assert_index_equal(result, expected)
1043+
1044+
result = index.get_level_values(1)
1045+
expected = pd.Index(['a', np.nan, 1], dtype=object)
1046+
tm.assert_index_equal(result, expected)
10351047

10361048
def test_reorder_levels(self):
10371049
# this blows up

0 commit comments

Comments
 (0)