熊猫:从多级列索引中删除一级?


242

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

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

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

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

3
最好有一个DataFrame方法同时对索引和列执行此操作。删除或选择索引级别。
索伦

@Sören查看stackoverflow.com/a/56080234/3198568droplevel可以通过参数在多级索引或列上工作axis
irene

Answers:


306

您可以使用MultiIndex.droplevel

>>> 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]

55
最好明确指出要删除的级别。级别从顶部开始为0索引。>>> df.columns = df.columns.droplevel(0)
Ted Petrou

6
如果您要删除的索引位于左侧(行)而不是顶部(列),则可以将“列”更改为“索引”,并使用相同的方法:>>> df.index = df.index.droplevel(1)
Idodo

7
在Panda版本0.23.4中,df.columns.droplevel()不再可用。
yoonghm '18

8
@yoonghm它在那儿,您可能只是在没有多索引的列上调用它
matt harrison 18/12/18

1
我有3个层次,想降到中等层次。我发现降低最低(级别[2]),然后最高(级别[0])效果最好。>>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)
凯尔C

65

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

df.columns = [col[1] for col in df.columns]

   b  c
0  1  2
1  3  4

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

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”。通过将名称与列表理解结合在一起可以避免这种情况。

df.columns = ['_'.join(col) for col in df.columns]

    A_x A_y B_y
0   1   2   8
1   3   4   9

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


2
[col[1] for col in df.columns]更直接df.columns.get_level_values(1)
Eric O Lebigot

2
有类似的需求,其中某些列具有空级别值。使用了以下内容:[col[0] if col[1] == '' else col[1] for col in df.columns]
Logan

43

另一种方法是使用.xs方法df基于的横截面重新分配。df

>>> 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

1
仅在整个列级别只有一个标签时,此方法才起作用。
泰德·彼得鲁

1
要删除第二级时不起作用。
索伦

如果要切片和拖放相同级别,这是一个很好的解决方案。如果您想在第二层切片(例如b),然后放下该层并留在第一层(a),则可以使用以下方法:df = df.xs('b', axis=1, level=1, drop_level=True)
Tiffany G. Wilson

27

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

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方法链滚动,这将非常有用。


这是“最佳”解决方案,因为将返回一个新的DataFrame而不是对其进行“就地”修改。
EliadL

16

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

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

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


这本质上就是Mint的第一个答案。现在,也无需指定名称列表(通常是乏味的),因为它是由给出的df.columns.get_level_values(1)
Eric O Lebigot

12

一个sum 与level = 1一起使用的小技巧(当level = 1唯一时,工作)

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

更常见的解决方案 get_level_values

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

4

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

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

1
这根本无法再现所需的输出。
Eric O Lebigot

根据发布的日期,您的Pandas版本中可能未包含下降级别(它已添加到2019年1月的稳定版本24.0中)
LinkBerest
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.