@@ -230,7 +230,7 @@ def _cleanup(self):
230230 @cache_readonly
231231 def _engine (self ):
232232 # property, for now, slow to look up
233- return self ._engine_type (weakref . ref (self ))
233+ return self ._engine_type (lambda : self . values , len (self ))
234234
235235 def _get_level_number (self , level ):
236236 if not isinstance (level , int ):
@@ -752,7 +752,10 @@ def isin(self, values):
752752 is_contained : ndarray (boolean dtype)
753753 """
754754 value_set = set (values )
755- return lib .ismember (self , value_set )
755+ return lib .ismember (self ._array_values (), value_set )
756+
757+ def _array_values (self ):
758+ return self
756759
757760 def _get_method (self , method ):
758761 if method :
@@ -1223,14 +1226,8 @@ def __new__(cls, levels=None, labels=None, sortorder=None, names=None):
12231226 levels = [_ensure_index (lev ) for lev in levels ]
12241227 labels = [np .asarray (labs , dtype = np .int_ ) for labs in labels ]
12251228
1226- values = [ndtake (lev .values , lab )
1227- for lev , lab in zip (levels , labels )]
1228-
1229- # Need to box timestamps, etc.
1230- values = _clean_arrays (values )
1231-
1232- subarr = lib .fast_zip (values ).view (cls )
1233-
1229+ # v3, 0.8.0
1230+ subarr = np .empty (0 , dtype = object ).view (cls )
12341231 subarr .levels = levels
12351232 subarr .labels = labels
12361233
@@ -1267,14 +1264,42 @@ def copy(self, order='C'):
12671264 cp .sortorder = self .sortorder
12681265 return cp
12691266
1267+ def _array_values (self ):
1268+ # hack for various methods
1269+ return self .values
1270+
12701271 @property
12711272 def dtype (self ):
12721273 return np .dtype ('O' )
12731274
1275+ def __repr__ (self ):
1276+ output = 'MultiIndex\n %s'
1277+
1278+ options = np .get_printoptions ()
1279+ np .set_printoptions (threshold = 50 )
1280+
1281+ if len (self ) > 100 :
1282+ values = np .concatenate ([self [:50 ].values ,
1283+ self [- 50 :].values ])
1284+ else :
1285+ values = self .values
1286+ summary = np .array2string (values , max_line_width = 70 )
1287+
1288+ np .set_printoptions (threshold = options ['threshold' ])
1289+
1290+ return output % summary
1291+
1292+ def __len__ (self ):
1293+ return len (self .labels [0 ])
1294+
12741295 @property
12751296 def _constructor (self ):
12761297 return MultiIndex .from_tuples
12771298
1299+ @cache_readonly
1300+ def inferred_type (self ):
1301+ return 'mixed'
1302+
12781303 @staticmethod
12791304 def _from_elements (values , labels = None , levels = None , names = None ,
12801305 sortorder = None ):
@@ -1302,21 +1327,35 @@ def _get_level_number(self, level):
13021327 % (self .nlevels , level ))
13031328 return level
13041329
1330+ _tuples = None
1331+
13051332 @property
13061333 def values (self ):
1307- if self ._is_legacy_format :
1308- # for legacy MultiIndex
1309- values = [ndtake (np .asarray (lev ), lab )
1310- for lev , lab in zip (self .levels , self .labels )]
1311- return lib .fast_zip (values )
1312- else :
1334+ if self ._is_v2 :
13131335 return self .view (np .ndarray )
1336+ else :
1337+ if self ._tuples is not None :
1338+ return self ._tuples
13141339
1340+ values = [ndtake (lev .values , lab )
1341+ for lev , lab in zip (self .levels , self .labels )]
1342+
1343+ # Need to box timestamps, etc.
1344+ values = _clean_arrays (values )
1345+ self ._tuples = lib .fast_zip (values )
1346+ return self ._tuples
1347+
1348+ # fml
13151349 @property
1316- def _is_legacy_format (self ):
1350+ def _is_v1 (self ):
13171351 contents = self .view (np .ndarray )
13181352 return len (contents ) > 0 and not isinstance (contents [0 ], tuple )
13191353
1354+ @property
1355+ def _is_v2 (self ):
1356+ contents = self .view (np .ndarray )
1357+ return len (contents ) > 0 and isinstance (contents [0 ], tuple )
1358+
13201359 @property
13211360 def _has_complex_internals (self ):
13221361 # to disable groupby tricks
@@ -1458,7 +1497,7 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
14581497 -------
14591498 index : MultiIndex
14601499 """
1461- from pandas .core .categorical import Factor
1500+ from pandas .core .categorical import Categorical
14621501
14631502 if len (arrays ) == 1 :
14641503 name = None if names is None else names [0 ]
@@ -1467,7 +1506,7 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
14671506 levels = []
14681507 labels = []
14691508 for arr in arrays :
1470- factor = Factor .from_array (arr )
1509+ factor = Categorical .from_array (arr )
14711510 levels .append (factor .levels )
14721511 labels .append (factor .labels )
14731512
@@ -1539,7 +1578,6 @@ def __setstate__(self, state):
15391578 self .sortorder = sortorder
15401579
15411580 def __getitem__ (self , key ):
1542- arr_idx = self .view (np .ndarray )
15431581 if np .isscalar (key ):
15441582 return tuple (lev [lab [key ]]
15451583 for lev , lab in zip (self .levels , self .labels ))
@@ -1551,11 +1589,10 @@ def __getitem__(self, key):
15511589 # cannot be sure whether the result will be sorted
15521590 sortorder = None
15531591
1554- new_tuples = arr_idx [ key ]
1592+ result = np . empty ( 0 , dtype = object ). view ( type ( self ))
15551593 new_labels = [lab [key ] for lab in self .labels ]
15561594
15571595 # an optimization
1558- result = new_tuples .view (MultiIndex )
15591596 result .levels = list (self .levels )
15601597 result .labels = new_labels
15611598 result .sortorder = sortorder
@@ -1759,11 +1796,8 @@ def sortlevel(self, level=0, ascending=True):
17591796 indexer = com ._ensure_platform_int (indexer )
17601797 new_labels = [lab .take (indexer ) for lab in self .labels ]
17611798
1762- new_index = MultiIndex ._from_elements (self .values .take (indexer ),
1763- labels = new_labels ,
1764- levels = self .levels ,
1765- names = self .names ,
1766- sortorder = level )
1799+ new_index = MultiIndex (labels = new_labels , levels = self .levels ,
1800+ names = self .names , sortorder = level )
17671801
17681802 return new_index , indexer
17691803
@@ -1800,15 +1834,13 @@ def get_indexer(self, target, method=None, limit=None):
18001834 target = _ensure_index (target )
18011835
18021836 target_index = target
1803- if isinstance (target , MultiIndex ) and target . _is_legacy_format :
1837+ if isinstance (target , MultiIndex ):
18041838 target_index = target .get_tuple_index ()
18051839
18061840 if target_index .dtype != object :
18071841 return np .ones (len (target_index )) * - 1
18081842
1809- self_index = self
1810- if self ._is_legacy_format :
1811- self_index = self .get_tuple_index ()
1843+ self_index = self .get_tuple_index ()
18121844
18131845 if method == 'pad' :
18141846 assert (self .is_unique and self .is_monotonic )
0 commit comments