pythonpandasdataframereplacemulti-index

How to replace one of the levels of a MultiIndex dataframe with one of its columns


I have a multiindex dataframe such as

multiindex = pd.MultiIndex.from_arrays(
    [list('aaaaasssssddddd'), [*range(3, 8), *range(1, 6), *range(2, 7)]],
    names=['contract', 'index']
)
df = pd.DataFrame(np.random.randn(15, 3), index=multiindex, columns=list('zxc'))
>>>
                       z         x         c
contract index                              
a        3      0.354879  0.206557  0.308081
         4      0.822102 -0.425685  1.973288
         5     -0.801313 -2.101411 -0.707400
         6     -0.740651 -0.564597 -0.975532
         7     -0.310679  0.515918 -1.213565
s        1     -0.175135  0.777495  0.100466
         2      2.295485  0.381226 -0.242292
         3     -0.753414  1.172924  0.679314
         4     -0.029526 -0.020714  1.546317
         5      0.250066 -1.673020 -0.773842
d        2     -0.602578 -0.761066 -1.117238
         3     -0.935758  0.448322 -2.135439
         4      0.808704 -0.604837 -0.319351
         5      0.321139  0.584896 -0.055951
         6      0.041849 -1.660013 -2.157992

Now I want to replace the index of index with the column c. That is to say, I want the result as

                           z         x
contract c                            
a         0.308081  0.354879  0.206557
          1.973288  0.822102 -0.425685
         -0.707400 -0.801313 -2.101411
         -0.975532 -0.740651 -0.564597
         -1.213565 -0.310679  0.515918
s         0.100466 -0.175135  0.777495
         -0.242292  2.295485  0.381226
          0.679314 -0.753414  1.172924
          1.546317 -0.029526 -0.020714
         -0.773842  0.250066 -1.673020
d        -1.117238 -0.602578 -0.761066
         -2.135439 -0.935758  0.448322
         -0.319351  0.808704 -0.604837
         -0.055951  0.321139  0.584896
         -2.157992  0.041849 -1.660013

I implement it in one way

df.reset_index().set_index(['contract', 'c']).drop(['index'], axis=1)

But it seems there are some duplicate steps because I manipulate the index three times. Is there is a more elegant way to achieve that?


Solution

  • Pandas' set_index method has append argument that controls whether to append columns to existing index or not; setting it True appends column "c" as an index. droplevel method removes index level (can remove column level too but removes index level by default).

    # convert column "c" into an index and remove "index" from index
    df = df.set_index('c', append=True).droplevel(level='index')