@@ -600,6 +600,33 @@ def stack_multiple(frame, level, dropna=True):
600
600
return result
601
601
602
602
603
+ def _stack_multi_column_index (columns : MultiIndex ) -> MultiIndex :
604
+ """Creates a MultiIndex from the first N-1 levels of this MultiIndex."""
605
+ if len (columns .levels ) <= 2 :
606
+ return columns .levels [0 ]._rename (name = columns .names [0 ])
607
+
608
+ levs = [
609
+ [lev [c ] if c >= 0 else None for c in codes ]
610
+ for lev , codes in zip (columns .levels [:- 1 ], columns .codes [:- 1 ])
611
+ ]
612
+
613
+ # Remove duplicate tuples in the MultiIndex.
614
+ tuples = zip (* levs )
615
+ unique_tuples = (key for key , _ in itertools .groupby (tuples ))
616
+ new_levs = zip (* unique_tuples )
617
+
618
+ # The dtype of each level must be explicitly set to avoid inferring the wrong type.
619
+ # See GH-36991.
620
+ return MultiIndex .from_arrays (
621
+ [
622
+ # Not all indices can accept None values.
623
+ Index (new_lev , dtype = lev .dtype ) if None not in new_lev else new_lev
624
+ for new_lev , lev in zip (new_levs , columns .levels )
625
+ ],
626
+ names = columns .names [:- 1 ],
627
+ )
628
+
629
+
603
630
def _stack_multi_columns (frame , level_num = - 1 , dropna = True ):
604
631
def _convert_level_number (level_num , columns ):
605
632
"""
@@ -634,20 +661,7 @@ def _convert_level_number(level_num, columns):
634
661
level_to_sort = _convert_level_number (0 , this .columns )
635
662
this = this .sort_index (level = level_to_sort , axis = 1 )
636
663
637
- # tuple list excluding level for grouping columns
638
- if len (frame .columns .levels ) > 2 :
639
- levs = []
640
- for lev , level_codes in zip (this .columns .levels [:- 1 ], this .columns .codes [:- 1 ]):
641
- if - 1 in level_codes :
642
- lev = np .append (lev , None )
643
- levs .append (np .take (lev , level_codes ))
644
- tuples = list (zip (* levs ))
645
- unique_groups = [key for key , _ in itertools .groupby (tuples )]
646
- new_names = this .columns .names [:- 1 ]
647
- new_columns = MultiIndex .from_tuples (unique_groups , names = new_names )
648
- else :
649
- new_columns = this .columns .levels [0 ]._rename (name = this .columns .names [0 ])
650
- unique_groups = new_columns
664
+ new_columns = _stack_multi_column_index (this .columns )
651
665
652
666
# time to ravel the values
653
667
new_data = {}
@@ -658,7 +672,7 @@ def _convert_level_number(level_num, columns):
658
672
level_vals_used = np .take (level_vals_nan , level_codes )
659
673
levsize = len (level_codes )
660
674
drop_cols = []
661
- for key in unique_groups :
675
+ for key in new_columns :
662
676
try :
663
677
loc = this .columns .get_loc (key )
664
678
except KeyError :
0 commit comments