@@ -600,6 +600,33 @@ def stack_multiple(frame, level, dropna=True):
600600 return result
601601
602602
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+
603630def _stack_multi_columns (frame , level_num = - 1 , dropna = True ):
604631 def _convert_level_number (level_num , columns ):
605632 """
@@ -634,20 +661,7 @@ def _convert_level_number(level_num, columns):
634661 level_to_sort = _convert_level_number (0 , this .columns )
635662 this = this .sort_index (level = level_to_sort , axis = 1 )
636663
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 )
651665
652666 # time to ravel the values
653667 new_data = {}
@@ -658,7 +672,7 @@ def _convert_level_number(level_num, columns):
658672 level_vals_used = np .take (level_vals_nan , level_codes )
659673 levsize = len (level_codes )
660674 drop_cols = []
661- for key in unique_groups :
675+ for key in new_columns :
662676 try :
663677 loc = this .columns .get_loc (key )
664678 except KeyError :
0 commit comments