将 Pandas 的多重索引转换为列

262

我有一个具有2个索引级别的数据框:

                         value
Trial    measurement
    1              0        13
                   1         3
                   2         4
    2              0       NaN
                   1        12
    3              0        34 

我希望你能够将这个变成这样:

Trial    measurement       value

    1              0        13
    1              1         3
    1              2         4
    2              0       NaN
    2              1        12
    3              0        34 

我应该如何最好地做到这一点?

我需要这样做是因为我想像这里的说明那样聚合数据,但如果我的列正在用作索引,我就无法像那样选择它们。


5
你想要第一个建议。使用 .reset_index() 可以将 Series 的索引重置,从而去除多级索引。 - TomAugspurger
1
非常感谢,我实际上浏览了很多内容,但“将多级索引转换为列”和类似的查询总是让我找到那些想要透视其数据框的线程... - TheChymera
3
当你已经知道答案时,寻找答案会更容易 :) - TomAugspurger
8个回答

324

reset_index() 是一个 pandas DataFrame 方法,可以将索引值转换为数据框中的列。参数的默认设置是 drop=False(这将保留索引值作为列)。

只需在数据框名称后调用.reset_index()即可。

df = df.reset_index()  

4
对于我遇到的情况,即使使用 inplace 参数,重置索引也无法起作用。替代方案是将新重置的数据框分配给一个新的变量:df2 = df.reset_index()。 - Gorkem
25
要仅重置特定级别,请使用df.reset_index(level=[...]) - cs95
1
或者副作用(可能更快)的方法:df.reset_index(inplace=True) - Owen
1
使用df.reset_index(names=['a', 'b'])为生成的列提供名称/替代名称。 - kva1966

38

这个并不适用于你的情况,但对于其他人可能会有帮助(比如像我刚刚五分钟前一样)。如果一个多重索引有相同的名称,就像这样:

                         value
Trial        Trial
    1              0        13
                   1         3
                   2         4
    2              0       NaN
                   1        12
    3              0        34 

df.reset_index(inplace=True)会失败,因为创建的列不能具有相同的名称。

因此,您需要使用df.index = df.index.set_names(['Trial', 'measurement'])来重命名多级索引以获取:

                           value
Trial    measurement       

    1              0        13
    1              1         3
    1              2         4
    2              0       NaN
    2              1        12
    3              0        34 

然后使用 df.reset_index(inplace=True) 就能完美解决问题。

我在对名为 live_date 的日期列(不是索引)按年份和月份进行分组后,遇到了这个问题,这意味着年份和月份都被命名为 live_date


1
如何让试验值重复出现?我有同样的问题,它可以工作,但是我的值不会重复出现。 - Rich

25

在某些情况下,df.reset_index() 无法使用(例如,当您需要索引时)。在这种情况下,使用 index.get_level_values() 直接访问索引值:

df['Trial'] = df.index.get_level_values(0)
df['measurement'] = df.index.get_level_values(1)

这将为各列分配索引值并且保留索引。

有关详细信息,请参见文档


3
非常有用!可以用更简单的语言来实现,例如:df['measurement'] = df.index.values(1)。请注意,我已尽力保留原文的意思和语境。 - Zizzipupp

19

正如@cs95在评论中提到的那样,如果只想降低一个级别,请使用:

df.reset_index(level=[...])

这样可以避免在重置后重新定义所需的索引。


5

我也遇到了Karl的问题。我只是将聚合列重新命名,然后重置索引。

df = pd.DataFrame(df.groupby(['arms', 'success'])['success'].sum()).rename(columns={'success':'sum'})

enter image description here

df = df.reset_index()

enter image description here


3

简短易懂

df2 = pd.DataFrame({'test_col': df['test_col'].describe()})
df2 = df2.reset_index()

1

在不是每一列都有多个索引级别的情况下,可能会有帮助的解决方案:

df.columns = df.columns.map(''.join)

1
类似于Alex solution的更通用形式。它保持索引不变,并将索引级别作为新列添加,列名与索引级别相对应。
for i in df.index.names:
    df[i] = df.index.get_level_values(i)

给出新的列'Trial'和'measurement'
                   value Trial    measurement
Trial measurement             
    1           0     13     1              0     
                1      3     1              1     
                2      4     1              2     
  ...  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接