@@ -1162,6 +1162,11 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
1162
1162
MultiIndex.from_product : Make a MultiIndex from cartesian product
1163
1163
of iterables
1164
1164
"""
1165
+ if not is_list_like (arrays ):
1166
+ raise TypeError ("Input must be a list / sequence of array-likes." )
1167
+ elif is_iterator (arrays ):
1168
+ arrays = list (arrays )
1169
+
1165
1170
# Check if lengths of all arrays are equal or not,
1166
1171
# raise ValueError, if not
1167
1172
for i in range (1 , len (arrays )):
@@ -1206,6 +1211,11 @@ def from_tuples(cls, tuples, sortorder=None, names=None):
1206
1211
MultiIndex.from_product : Make a MultiIndex from cartesian product
1207
1212
of iterables
1208
1213
"""
1214
+ if not is_list_like (tuples ):
1215
+ raise TypeError ('Input must be a list /sequence of tuple-likes.' )
1216
+ elif is_iterator (tuples ):
1217
+ tuples = list (tuples )
1218
+
1209
1219
if len (tuples ) == 0 :
1210
1220
if names is None :
1211
1221
msg = 'Cannot infer number of levels from empty list'
@@ -1260,6 +1270,11 @@ def from_product(cls, iterables, sortorder=None, names=None):
1260
1270
from pandas .core .categorical import _factorize_from_iterables
1261
1271
from pandas .core .reshape .util import cartesian_product
1262
1272
1273
+ if not is_list_like (iterables ):
1274
+ raise TypeError ("Input must be a list / sequence of iterables." )
1275
+ elif is_iterator (iterables ):
1276
+ iterables = list (iterables )
1277
+
1263
1278
labels , levels = _factorize_from_iterables (iterables )
1264
1279
labels = cartesian_product (labels )
1265
1280
return MultiIndex (levels , labels , sortorder = sortorder , names = names )
@@ -1365,29 +1380,31 @@ def remove_unused_levels(self):
1365
1380
new_labels = []
1366
1381
1367
1382
changed = False
1368
- for lev , lab in zip (self .levels , self .labels ):
1383
+ for idx , (lev , lab ) in enumerate (zip (self .levels , self .labels )):
1384
+ na_idxs = np .where (lab == - 1 )[0 ]
1385
+
1386
+ if len (na_idxs ):
1387
+ lab = np .delete (lab , na_idxs )
1369
1388
1370
1389
uniques = algos .unique (lab )
1371
- na_idx = np .where (uniques == - 1 )[0 ]
1372
1390
1373
1391
# nothing unused
1374
- if len (uniques ) != len (lev ) + len ( na_idx ) :
1392
+ if len (uniques ) != len (lev ):
1375
1393
changed = True
1376
1394
1377
- if len (na_idx ):
1378
- # Just ensure that -1 is in first position:
1379
- uniques [[0 , na_idx [0 ]]] = uniques [[na_idx [0 ], 0 ]]
1380
-
1381
1395
# labels get mapped from uniques to 0:len(uniques)
1382
- # -1 (if present) is mapped to last position
1383
- label_mapping = np .zeros (len (lev ) + len (na_idx ))
1384
- # ... and reassigned value -1:
1385
- label_mapping [uniques ] = np .arange (len (uniques )) - len (na_idx )
1396
+ label_mapping = np .zeros (len (lev ))
1397
+ label_mapping [uniques ] = np .arange (len (uniques ))
1386
1398
1387
1399
lab = label_mapping [lab ]
1388
1400
1389
1401
# new levels are simple
1390
- lev = lev .take (uniques [len (na_idx ):])
1402
+ lev = lev .take (uniques )
1403
+
1404
+ if len (na_idxs ):
1405
+ lab = np .insert (lab , na_idxs - np .arange (len (na_idxs )), - 1 )
1406
+ else :
1407
+ lab = self .labels [idx ]
1391
1408
1392
1409
new_levels .append (lev )
1393
1410
new_labels .append (lab )
0 commit comments