Search code examples
pythonpandasmulti-index

Roll levels of a MultiIndex


Suppose I have a dataframe where my columns are a MultiIndex

col = pd.MultiIndex.from_product(
    [[1, 2], ['A', 'B'], ['First', 'Second']],
    names=['Cat', 'Dog', 'Bird']
)
dat = np.arange(16).reshape(2, -1)
df = pd.DataFrame(dat, columns=col)
df

Cat      1                         2                    
Dog      A            B            A            B       
Bird First Second First Second First Second First Second
0        0      1     2      3     4      5     6      7
1        8      9    10     11    12     13    14     15

I want to adjust the columns such that the Bird level is on top, Cat level shifts down to the middle, and Dog goes to the bottom.

Attempt 1

Using swaplevel can be used in succession but feels clumsy to create a whole dataframe in the middle just to augment the columns.

df.swaplevel(0, 2, 1).swaplevel(1, 2, 1).sort_index(1)

Bird First             Second            
Cat      1       2          1       2    
Dog      A   B   A   B      A   B   A   B
0        0   2   4   6      1   3   5   7
1        8  10  12  14      9  11  13  15

Attempt 2

Create new MultiIndex should be efficient but is not as intuitive and may be unnecessarily verbose.

def roll(x):
    return x[-1:] + x[:-1]

df.set_axis(
    pd.MultiIndex.from_tuples(
        [roll(x) for x in df.columns.values],
        names=roll(df.columns.names)
    ), axis=1, inplace=False).sort_index(1)

Bird First             Second            
Cat      1       2          1       2    
Dog      A   B   A   B      A   B   A   B
0        0   2   4   6      1   3   5   7
1        8  10  12  14      9  11  13  15

Question

Is there a clean and intuitive way to do this without creating an intermediate dataframe in the middle?


Solution

  • Is this what you need Sir ? Using reorder_levels:

    df.reorder_levels(['Bird','Cat','Dog'],axis=1).sort_index(level=0,axis=1)
    Out[396]: 
    Bird First             Second            
    Cat      1       2          1       2    
    Dog      A   B   A   B      A   B   A   B
    0        0   2   4   6      1   3   5   7
    1        8  10  12  14      9  11  13  15