(frame: DataFrame, level: list[int])
| 970 | |
| 971 | |
| 972 | def stack_v3(frame: DataFrame, level: list[int]) -> Series | DataFrame: |
| 973 | if frame.columns.nunique() != len(frame.columns): |
| 974 | raise ValueError("Columns with duplicate values are not supported in stack") |
| 975 | if not len(level): |
| 976 | return frame |
| 977 | set_levels = set(level) |
| 978 | stack_cols = frame.columns._drop_level_numbers( |
| 979 | [k for k in range(frame.columns.nlevels - 1, -1, -1) if k not in set_levels] |
| 980 | ) |
| 981 | |
| 982 | result: Series | DataFrame |
| 983 | if not isinstance(frame.columns, MultiIndex): |
| 984 | # GH#58817 Fast path when we're stacking the columns of a non-MultiIndex. |
| 985 | # When columns are homogeneous EAs, we pass through object |
| 986 | # dtype but this is still slightly faster than the normal path. |
| 987 | if len(frame.columns) > 0 and frame._is_homogeneous_type: |
| 988 | dtype = frame._mgr.blocks[0].dtype |
| 989 | else: |
| 990 | dtype = None |
| 991 | result = frame._constructor_sliced( |
| 992 | frame._values.reshape(-1, order="F"), dtype=dtype |
| 993 | ) |
| 994 | else: |
| 995 | result = stack_reshape(frame, level, set_levels, stack_cols) |
| 996 | |
| 997 | # Construct the correct MultiIndex by combining the frame's index and |
| 998 | # stacked columns. |
| 999 | ratio = 0 if frame.empty else len(result) // len(frame) |
| 1000 | |
| 1001 | index_levels: list | FrozenList |
| 1002 | if isinstance(frame.index, MultiIndex): |
| 1003 | index_levels = frame.index.levels |
| 1004 | index_codes = list(np.tile(frame.index.codes, (1, ratio))) |
| 1005 | else: |
| 1006 | codes, uniques = factorize(frame.index, use_na_sentinel=False) |
| 1007 | index_levels = [uniques] |
| 1008 | index_codes = list(np.tile(codes, (1, ratio))) |
| 1009 | |
| 1010 | if len(level) > 1: |
| 1011 | # Arrange columns in the order we want to take them, e.g. level=[2, 0, 1] |
| 1012 | sorter = np.argsort(level) |
| 1013 | assert isinstance(stack_cols, MultiIndex) |
| 1014 | ordered_stack_cols = stack_cols._reorder_ilevels(sorter) |
| 1015 | else: |
| 1016 | ordered_stack_cols = stack_cols |
| 1017 | ordered_stack_cols_unique = ordered_stack_cols.unique() |
| 1018 | if isinstance(ordered_stack_cols, MultiIndex): |
| 1019 | column_levels = ordered_stack_cols.levels |
| 1020 | column_codes = ordered_stack_cols.drop_duplicates().codes |
| 1021 | else: |
| 1022 | column_levels = [ordered_stack_cols_unique] |
| 1023 | column_codes = [factorize(ordered_stack_cols_unique, use_na_sentinel=False)[0]] |
| 1024 | |
| 1025 | # error: Incompatible types in assignment (expression has type "list[ndarray[Any, |
| 1026 | # dtype[Any]]]", variable has type "FrozenList") |
| 1027 | column_codes = [np.repeat(codes, len(frame)) for codes in column_codes] # type: ignore[assignment] |
| 1028 | result.index = MultiIndex( |
| 1029 | levels=index_levels + column_levels, |
no test coverage detected