@@ -513,9 +513,7 @@ def stack(frame, level=-1, dropna=True):
513
513
"names are not unique." .format (level ))
514
514
raise ValueError (msg )
515
515
516
- if isinstance (level , int ) and level < 0 :
517
- level += frame .columns .nlevels
518
-
516
+ # Will also convert negative level numbers and check if out of bounds.
519
517
level = frame .columns ._get_level_number (level )
520
518
521
519
if isinstance (frame .columns , MultiIndex ):
@@ -547,6 +545,45 @@ def stack(frame, level=-1, dropna=True):
547
545
return Series (new_values , index = new_index )
548
546
549
547
548
+ def stack_multiple (frame , level , dropna = True ):
549
+ # If all passed levels match up to column names, no
550
+ # ambiguity about what to do
551
+ if all (lev in frame .columns .names for lev in level ):
552
+ result = frame
553
+ for lev in level :
554
+ result = stack (result , lev , dropna = dropna )
555
+
556
+ # Otherwise, level numbers may change as each successive level is stacked
557
+ elif all (isinstance (lev , int ) for lev in level ):
558
+ # As each stack is done, the level numbers decrease, so we need
559
+ # to account for that when level is a sequence of ints
560
+ result = frame
561
+ # _get_level_number() checks level numbers are in range and converts
562
+ # negative numbers to positive
563
+ level = [frame .columns ._get_level_number (lev ) for lev in level ]
564
+
565
+ # Can't iterate directly through level as we might need to change
566
+ # values as we go
567
+ for index in range (len (level )):
568
+ lev = level [index ]
569
+ result = stack (result , lev , dropna = dropna )
570
+ # Decrement all level numbers greater than current, as these
571
+ # have now shifted down by one
572
+ updated_level = []
573
+ for other in level :
574
+ if other > lev :
575
+ updated_level .append (other - 1 )
576
+ else :
577
+ updated_level .append (other )
578
+ level = updated_level
579
+
580
+ else :
581
+ raise ValueError ("level should contain all level names or all level numbers, "
582
+ "not a mixture of the two." )
583
+
584
+ return result
585
+
586
+
550
587
def _stack_multi_columns (frame , level = - 1 , dropna = True ):
551
588
this = frame .copy ()
552
589
0 commit comments