|
14 | 14 | from pandas.compat.numpy import function as nv
|
15 | 15 | from pandas import compat
|
16 | 16 |
|
17 |
| - |
18 | 17 | from pandas.types.common import (_ensure_int64,
|
19 | 18 | _ensure_platform_int,
|
20 | 19 | is_object_dtype,
|
@@ -73,6 +72,7 @@ class MultiIndex(Index):
|
73 | 72 | _levels = FrozenList()
|
74 | 73 | _labels = FrozenList()
|
75 | 74 | _comparables = ['names']
|
| 75 | + _engine_type = _index.MultiIndexEngine |
76 | 76 | rename = Index.set_names
|
77 | 77 |
|
78 | 78 | def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
|
@@ -114,7 +114,6 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None,
|
114 | 114 | result._verify_integrity()
|
115 | 115 | if _set_identity:
|
116 | 116 | result._reset_identity()
|
117 |
| - |
118 | 117 | return result
|
119 | 118 |
|
120 | 119 | def _verify_integrity(self, labels=None, levels=None):
|
@@ -613,6 +612,38 @@ def _get_level_number(self, level):
|
613 | 612 |
|
614 | 613 | _tuples = None
|
615 | 614 |
|
| 615 | + def _to_multiindex_structure(self): |
| 616 | + |
| 617 | + # return a structure that has an efficient representation |
| 618 | + # of the hashed values of the multi-index |
| 619 | + # as well as properties for interfacing with index.pyx |
| 620 | + # and hashtable.pyx |
| 621 | + from pandas.tools.hashing import hash_tuples |
| 622 | + |
| 623 | + class _MultiIndexStructure(object): |
| 624 | + def __init__(self, mi): |
| 625 | + self.nlevels = mi.nlevels |
| 626 | + self.length = len(mi) |
| 627 | + self.obj = mi |
| 628 | + self.values = hash_tuples(mi) |
| 629 | + |
| 630 | + def __len__(self): |
| 631 | + return self.length |
| 632 | + |
| 633 | + @property |
| 634 | + def is_lexsorted(self): |
| 635 | + return self.obj.is_lexsorted() |
| 636 | + |
| 637 | + @property |
| 638 | + def is_unique(self): |
| 639 | + return self.obj.is_unique |
| 640 | + |
| 641 | + return _MultiIndexStructure(self) |
| 642 | + |
| 643 | + @cache_readonly |
| 644 | + def _engine(self): |
| 645 | + return self._engine_type(lambda: self, len(self)) |
| 646 | + |
616 | 647 | @property
|
617 | 648 | def values(self):
|
618 | 649 | if self._tuples is not None:
|
@@ -846,7 +877,8 @@ def to_frame(self, index=True):
|
846 | 877 | from pandas import DataFrame
|
847 | 878 | result = DataFrame({(name or level): self.get_level_values(level)
|
848 | 879 | for name, level in
|
849 |
| - zip(self.names, range(len(self.levels)))}) |
| 880 | + zip(self.names, range(len(self.levels)))}, |
| 881 | + copy=False) |
850 | 882 | if index:
|
851 | 883 | result.index = self
|
852 | 884 | return result
|
@@ -1472,29 +1504,23 @@ def get_indexer(self, target, method=None, limit=None, tolerance=None):
|
1472 | 1504 | method = missing.clean_reindex_fill_method(method)
|
1473 | 1505 | target = _ensure_index(target)
|
1474 | 1506 |
|
1475 |
| - target_index = target |
1476 |
| - if isinstance(target, MultiIndex): |
1477 |
| - target_index = target._tuple_index |
1478 |
| - |
1479 |
| - if not is_object_dtype(target_index.dtype): |
1480 |
| - return np.ones(len(target_index)) * -1 |
| 1507 | + if not isinstance(target, MultiIndex): |
| 1508 | + target = MultiIndex.from_tuples(target) |
1481 | 1509 |
|
1482 | 1510 | if not self.is_unique:
|
1483 | 1511 | raise Exception('Reindexing only valid with uniquely valued Index '
|
1484 | 1512 | 'objects')
|
1485 | 1513 |
|
1486 |
| - self_index = self._tuple_index |
1487 |
| - |
1488 | 1514 | if method == 'pad' or method == 'backfill':
|
1489 | 1515 | if tolerance is not None:
|
1490 | 1516 | raise NotImplementedError("tolerance not implemented yet "
|
1491 | 1517 | 'for MultiIndex')
|
1492 |
| - indexer = self_index._get_fill_indexer(target, method, limit) |
| 1518 | + indexer = self._get_fill_indexer(target, method, limit) |
1493 | 1519 | elif method == 'nearest':
|
1494 | 1520 | raise NotImplementedError("method='nearest' not implemented yet "
|
1495 | 1521 | 'for MultiIndex; see GitHub issue 9365')
|
1496 | 1522 | else:
|
1497 |
| - indexer = self_index._engine.get_indexer(target._values) |
| 1523 | + indexer = self._engine.get_indexer(target) |
1498 | 1524 |
|
1499 | 1525 | return _ensure_platform_int(indexer)
|
1500 | 1526 |
|
@@ -1561,17 +1587,6 @@ def reindex(self, target, method=None, level=None, limit=None,
|
1561 | 1587 |
|
1562 | 1588 | return target, indexer
|
1563 | 1589 |
|
1564 |
| - @cache_readonly |
1565 |
| - def _tuple_index(self): |
1566 |
| - """ |
1567 |
| - Convert MultiIndex to an Index of tuples |
1568 |
| -
|
1569 |
| - Returns |
1570 |
| - ------- |
1571 |
| - index : Index |
1572 |
| - """ |
1573 |
| - return Index(self._values) |
1574 |
| - |
1575 | 1590 | def get_slice_bound(self, label, side, kind):
|
1576 | 1591 |
|
1577 | 1592 | if not isinstance(label, tuple):
|
|
0 commit comments