Skip to content

Commit 39684cb

Browse files
committed
BUG: support tupleization for mixed levels
closes #18505
1 parent f745e52 commit 39684cb

File tree

4 files changed

+20
-15
lines changed

4 files changed

+20
-15
lines changed

doc/source/whatsnew/v0.22.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ Indexing
147147
- Bug in :func:`DataFrame.groupby` where tuples were interpreted as lists of keys rather than as keys (:issue:`17979`, :issue:`18249`)
148148
- Bug in :func:`MultiIndex.remove_unused_levels`` which would fill nan values (:issue:`18417`)
149149
- Bug in :func:`MultiIndex.from_tuples`` which would fail to take zipped tuples in python3 (:issue:`18434`)
150+
- Bug in :class:`Index`` initialization from list of mixed type tuples (:issue:`18505`)
150151
- Bug in :class:`IntervalIndex` where empty and purely NA data was constructed inconsistently depending on the construction method (:issue:`18421`)
151152
- Bug in ``IntervalIndex.symmetric_difference()`` where the symmetric difference with a non-``IntervalIndex`` did not raise (:issue:`18475`)
152153

pandas/core/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -874,8 +874,9 @@ def _map_values(self, mapper, na_action=None):
874874
# convert to an Series for efficiency.
875875
# we specify the keys here to handle the
876876
# possibility that they are tuples
877-
from pandas import Series
878-
mapper = Series(mapper, index=mapper.keys())
877+
from pandas import Series, Index
878+
index = Index(mapper, tupleize_cols=False)
879+
mapper = Series(mapper, index=index)
879880

880881
if isinstance(mapper, ABCSeries):
881882
# Since values were input this means we came from either

pandas/core/indexes/base.py

+6-13
Original file line numberDiff line numberDiff line change
@@ -353,22 +353,15 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
353353
elif data is None or is_scalar(data):
354354
cls._scalar_data_error(data)
355355
else:
356-
if (tupleize_cols and isinstance(data, list) and data and
357-
isinstance(data[0], tuple)):
358-
356+
if tupleize_cols and is_list_like(data) and data:
357+
if is_iterator(data):
358+
data = list(data)
359359
# we must be all tuples, otherwise don't construct
360360
# 10697
361361
if all(isinstance(e, tuple) for e in data):
362-
try:
363-
# must be orderable in py3
364-
if compat.PY3:
365-
sorted(data)
366-
from .multi import MultiIndex
367-
return MultiIndex.from_tuples(
368-
data, names=name or kwargs.get('names'))
369-
except (TypeError, KeyError):
370-
# python2 - MultiIndex fails on mixed types
371-
pass
362+
from .multi import MultiIndex
363+
return MultiIndex.from_tuples(
364+
data, names=name or kwargs.get('names'))
372365
# other iterable of some kind
373366
subarr = _asarray_tuplesafe(data, dtype=object)
374367
return Index(subarr, dtype=dtype, copy=copy, name=name, **kwargs)

pandas/tests/indexes/test_base.py

+10
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ def test_construction_list_mixed_tuples(self):
106106
assert isinstance(idx2, Index)
107107
assert not isinstance(idx2, MultiIndex)
108108

109+
# GH 18505 : valid mixed tuples
110+
idx3 = Index([(1, 2), (None, 4)])
111+
assert isinstance(idx3, MultiIndex)
112+
113+
idx4 = Index([(1, 2.), ('three', 4)])
114+
assert isinstance(idx4, MultiIndex)
115+
116+
idx5 = Index((x for x in list(idx4)))
117+
assert isinstance(idx5, MultiIndex)
118+
109119
def test_constructor_from_index_datetimetz(self):
110120
idx = pd.date_range('2015-01-01 10:00', freq='D', periods=3,
111121
tz='US/Eastern')

0 commit comments

Comments
 (0)