关于python:Pandas:从多级列索引中删除一级吗?

Pandas: drop a level from a multi-level column index?

如果我有一个多级列索引:

1
2
>>> cols = pd.MultiIndex.from_tuples([("a","b"), ("a","c")])
>>> pd.DataFrame([[1,2], [3,4]], columns=cols)
1
2
3
4
5
6
    a
   ---+--
    b | c
--+---+--
0 | 1 | 2
1 | 3 | 4

如何删除该索引的" a"级,所以我得到以下结果:

1
2
3
4
    b | c
--+---+--
0 | 1 | 2
1 | 3 | 4


您可以使用MultiIndex.droplevel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> cols = pd.MultiIndex.from_tuples([("a","b"), ("a","c")])
>>> df = pd.DataFrame([[1,2], [3,4]], columns=cols)
>>> df
   a  
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]
>>> df.columns = df.columns.droplevel()
>>> df
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]


删除索引的另一种方法是使用列表理解:

1
2
3
4
5
df.columns = [col[1] for col in df.columns]

   b  c
0  1  2
1  3  4

如果要合并两个级别的名称,例如下面的示例,其中最底层包含两个" y",则此策略也很有用:

1
2
3
4
5
6
7
cols = pd.MultiIndex.from_tuples([("A","x"), ("A","y"), ("B","y")])
df = pd.DataFrame([[1,2, 8 ], [3,4, 9]], columns=cols)

   A     B
   x  y  y
0  1  2  8
1  3  4  9

删除顶层将留下两列带有索引" y"。可以通过将名称与列表理解一起加入来避免这种情况。

1
2
3
4
5
df.columns = ['_'.join(col) for col in df.columns]

    A_x A_y B_y
0   1   2   8
1   3   4   9

这是我在进行分组排序后遇到的一个问题,花了一段时间才找到另一个解决问题的方法。我在这里针对特定情况调整了该解决方案。


执行此操作的另一种方法是使用.xs方法基于df的横截面重新分配df

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> df

    a
    b   c
0   1   2
1   3   4

>>> df = df.xs('a', axis=1, drop_level=True)

    # 'a' : key on which to get cross section
    # axis=1 : get cross section of column
    # drop_level=True : returns cross section without the multilevel index

>>> df

    b   c
0   1   2
1   3   4


您也可以通过重命名列来实现:

df.columns = ['a', 'b']

这涉及一个手动步骤,但是可以选择,特别是如果您最终要重命名数据框。


从Pandas 0.24.0开始,我们现在可以使用DataFrame.droplevel():

1
2
3
4
5
6
7
8
cols = pd.MultiIndex.from_tuples([("a","b"), ("a","c")])
df = pd.DataFrame([[1,2], [3,4]], columns=cols)

df.droplevel(0, axis=1)

#   b  c
#0  1  2
#1  3  4

如果要保持DataFrame方法链滚动,这将非常有用。


使用sum和level = 1的一个小技巧(当level = 1时都是唯一的)

1
2
3
4
5
df.sum(level=1,axis=1)
Out[202]:
   b  c
0  1  2
1  3  4

更常见的解决方案get_level_values

1
2
3
4
5
6
df.columns=df.columns.get_level_values(1)
df
Out[206]:
   b  c
0  1  2
1  3  4


由于我不知道为什么我的droplevel()函数不起作用,所以我一直在努力解决这个问题。遍历多个,并了解表中的" a"是列名," b"," c"是索引。这样做会有所帮助

1
2
df.columns.name = None
df.reset_index() #make index become label