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

Posted

技术标签:

【中文标题】熊猫:从多级列索引中删除一个级别?【英文标题】:Pandas: drop a level from a multi-level column index? 【发布时间】:2014-04-09 14:53:17 【问题描述】:

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

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

如何删除该索引的“a”级别,所以我最终得到:

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

【问题讨论】:

如果有一个 DataFrame 方法对索引和列都执行此操作,那就太好了。删除或选择索引级别。 @Sören 查看***.com/a/56080234/3198568。 droplevel 作品可以通过参数axis 作用于多级索引或列。 【参考方案1】:

你可以使用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]

【讨论】:

最好明确说明要删除的级别。级别从顶部开始为 0 索引。 >>> df.columns = df.columns.droplevel(0) 如果您要删除的索引在左侧(行)侧而不是顶部(列)侧,您可以将“列”更改为“索引”并使用相同的方法:@ 987654325@ 在 Panda 0.23.4 版中,df.columns.droplevel() 不再可用。 @yoonghm 它在那里,你可能只是在没有多索引的列上调用它 我有三层深度,想降到中层。我发现删除最低的(级别 [2])然后是最高的(级别 [0])效果最好。 >>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)【参考方案2】:

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

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

这是我在进行 groupby 后遇到的一个问题,我花了一段时间才找到解决它的 this other question。我根据这里的具体情况调整了该解决方案。

【讨论】:

[col[1] for col in df.columns] 更直接的是df.columns.get_level_values(1) 有类似的需求,其中一些列的级别值为空。使用以下内容:[col[0] if col[1] == '' else col[1] for col in df.columns]【参考方案3】:

从 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,而不是“就地”修改它。 df.droplevel(0, axis='columns') 更加明确易懂 我会永远来这里,因为我总是忘记设置axis=1【参考方案4】:

另一种方法是使用.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

【讨论】:

这仅适用于整个列级别只有一个标签的情况。 当你想掉第二层时不起作用。 如果您想在同一级别进行切片和删除,这是一个不错的解决方案。如果您想在第二层(比如b)上切片,然后删除该层并保留第一层(a),以下方法将起作用:df = df.xs('b', axis=1, level=1, drop_level=True)【参考方案5】:

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

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

这涉及手动步骤,但如果您最终要重命名数据框,则可能是一种选择。

【讨论】:

这基本上就是 Mint 的第一个答案所做的。现在,也不需要指定名称列表(这通常很乏味),因为它是由df.columns.get_level_values(1) 提供给您的。【参考方案6】:

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

【讨论】:

【参考方案7】:

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

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

【讨论】:

这根本不会重现所需的输出。 根据发布日期,您的 Pandas 版本中可能未包含 drop level(它已于 2019 年 1 月添加到稳定版本 24.0)

以上是关于熊猫:从多级列索引中删除一个级别?的主要内容,如果未能解决你的问题,请参考以下文章

从熊猫数据框的列索引中获取字符串列表

NumPy:在子矩阵/块和相应的行、列索引中找到最小值

熊猫数据框检查索引是不是存在于多索引中

如何在多级列(熊猫)中将一级索引转换为新级别

熊猫列多索引中的缺失值

如何删除熊猫数据透视表中的多级索引