重命名具有任意顺序和重复列名的多索引列

Posted

技术标签:

【中文标题】重命名具有任意顺序和重复列名的多索引列【英文标题】:Renaming multiindex columns with arbitrary order and duplicate column names 【发布时间】:2019-01-19 20:07:31 【问题描述】:

我有一个DataFrame overview(这个问题的缩写)。

>>> import pandas as pd
>>> import numpy as np
>>>
>>> index = pd.Index(['Abbott PLC', 'Abbott, Rogahn and Bednar'], dtype='object', name='Account Name')
>>> columns = pd.MultiIndex(levels=[['total', 'quantity'], ['count', 'sum']], labels=[[0, 0, 1], [1, 0, 1]])
>>> values = np.array([[755.44,   1.  ,  19.  ], [615.6 ,   1.  ,  18.  ]])
>>> 
>>> overview = pd.DataFrame(values, columns=columns, index=index)
>>> overview
                            total       quantity
                              sum count      sum
Account Name                                    
Abbott PLC                 755.44   1.0     19.0
Abbott, Rogahn and Bednar  615.60   1.0     18.0

列名很奇怪,因为在我的实际代码中,此结果是从 DataFrame df 派生而来的,具有以下分组操作。

aggregators = 'total': ['sum', 'count'], 'quantity': 'sum'
overview = df.groupby('Account Name')['total', 'quantity'].agg(aggregators)

我想重命名overview的列,想要的结果是这样的:

                            gross  checkouts  items
Account Name                                       
Abbott PLC                 755.44        1.0   19.0
Abbott, Rogahn and Bednar  615.60        1.0   18.0

我不能简单地使用overview.columns = ['gross', 'checkouts', 'items'] 或this similar question 的答案,因为在使用agg 之后,列的顺序是任意的。 (应用rename 也似乎很棘手,因为重复名称'sum'。)

目前,我正在通过将OrderedDict 用于aggregators 来解决此问题,因此overview 具有确定性的列序数。但是假设 overview 的创建不能在上游修复,我将如何优雅地达到我想要的结果?

【问题讨论】:

如果你扁平化并加入你的列,你会得到像 Index(['total_sum', 'total_count', 'quantity_sum'], dtype='object') 这样的东西,这将是独一无二的,如果我理解正确的话,你可以重命名。跨度> @user3483203 听起来很有希望,请随时写一个答案,教我扁平化和加入过程。 试试overview.columns = ['_'.join(col).strip() for col in overview.columns.values],看看是不是你想走的路,如果是,我会写出来作为答案。 @user3483203 似乎工作正常。我想知道是否有更“熊猫原生”的解决方案,但现在它可以解决问题! 我不知道熊猫内置的更好方法,但很高兴我能提供帮助! 【参考方案1】:

您的数据框有一个 MultiIndex 作为列。有几种方法可以展平为常规索引:

pd.Index.map

overview.columns = overview.columns.map('_'.join)

列表理解 + f-strings

在 Python 3.6+ 中,您可以使用格式化的字符串文字 (PEP 498):

overview.columns = [f'i_j' for i, j in overview.columns]

列表理解 + str.format / str.join

对于 str.format 或str.join

overview.columns = ['i_j'.format(i, j) for i, j in overview.columns]

overview.columns = list(map('_'.join, overview.columns))

如果只重命名,可以直接使用字典映射:

d = ('total', 'sum'): 'gross', ('total', 'count'): 'checkouts',
     ('quantity', 'sum'): 'items'

overview.columns = np.vectorize(d.get)(overview.columns)

【讨论】:

谢谢。我知道如何从临时列名着手。为了完整起见,您可以考虑在答案中包含最终重命名。 @timgeb,当然,我还添加了一个更直接的方法,不需要中间重命名。 现在我明白了。容器overview.columns 的工作方式与其打印输出的建议完全不同。实际上,在这种情况下,我可以将其视为元组列表[('total', 'sum'), ('total', 'count'), ('quantity', 'sum')] @timgeb,正是如此。甚至还有一种从元组列表构造Index 的方法:pd.MultiIndex.from_tuples

以上是关于重命名具有任意顺序和重复列名的多索引列的主要内容,如果未能解决你的问题,请参考以下文章

加入数据框 - 一个具有多索引列,另一个没有

重命名多索引数据框熊猫[重复]

分配多索引列,同时保留索引级别值的顺序

使用 Pandas 从查找字典中重命名多索引行

数据透视表列重命名

熊猫重命名多级查找列名[重复]