【问题标题】:Python Pandas: Is Order Preserved When Using groupby() and agg()?Python Pandas:使用 groupby() 和 agg() 时是否保留顺序?
【发布时间】:2014-12-14 20:57:25
【问题描述】:

我经常使用 pandas 的 agg() 函数对 data.frame 的每一列运行汇总统计信息。例如,以下是生成均值和标准差的方法:

df = pd.DataFrame({'A': ['group1', 'group1', 'group2', 'group2', 'group3', 'group3'],
                   'B': [10, 12, 10, 25, 10, 12],
                   'C': [100, 102, 100, 250, 100, 102]})

>>> df
[output]
        A   B    C
0  group1  10  100
1  group1  12  102
2  group2  10  100
3  group2  25  250
4  group3  10  100
5  group3  12  102

在这两种情况下,将各个行发送到 agg 函数的顺序并不重要。但请考虑以下示例:

df.groupby('A').agg([np.mean, lambda x: x.iloc[1] ])

[output]

        mean  <lambda>  mean  <lambda>
A                                     
group1  11.0        12   101       102
group2  17.5        25   175       250
group3  11.0        12   101       102

在这种情况下,lambda 按预期运行,输出每组中的第二行。但是,我无法在 pandas 文档中找到任何暗示这在所有情况下都是正确的。我想将agg() 与加权平均函数一起使用,因此我想确保进入函数的行与它们在原始数据框中出现的顺序相同。

有谁知道,最好是通过文档或熊猫源代码中的某个地方,是否可以保证是这种情况?

【问题讨论】:

  • 是的,我看不到文档中保留订单的任何保证,因此依赖它似乎有点不明智。如果您的 B 列反映了排序,那么您可以在 lambda 中按 B 对每个组进行排序以确保。
  • 不幸的是,我想保持行按未包含在聚合中的列排序。数据框在agg() 调用之前排序,因此只有将其重新排序为groupby() 的一部分时才会出现问题。

标签: python pandas aggregate


【解决方案1】:

很遗憾,这个问题的答案是否定的。在过去的几天里,我创建了一个用于非均匀分块的算法,发现它不可能保留顺序,因为 groupby 引入了子帧,其中每个帧的关键是 groupby 输入。所以你最终得到:

allSubFrames = df.groupby("myColumnToOrderBy")
for orderKey, individualSubFrame in allSubFrames:
     do something...

因为它使用字典,你会失去排序。

如果您之后执行排序,如上所述,我刚刚测试了一个大型数据集,您最终会得到 O(n log n) 计算。

但是,我发现,例如,如果您按顺序订购了时间序列数据,并且要保留顺序,最好将排序列更改为列表,然后创建一个计数器来记录第一项每个时间序列。这会导致 O(n) 计算。

因此,基本上,如果您使用的是相对较小的数据集,上述建议的答案是合理的,但如果使用大数据集,您需要考虑避免使用 groupby 和 sort。而是使用:list(df['myColumnToOrderBy']) 和迭代器。

【讨论】:

  • 您能否在您的答案中添加一个简单的工作代码示例?
【解决方案2】:

参考: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html

API 接受“SORT”作为参数。

SORT 参数说明如下:

sort : bool,默认为 True 对组键进行排序。关闭此功能可获得更好的性能。请注意,这不会影响每组内的观察顺序。 Groupby 保留每个组内的行顺序

因此,很明显“Groupby”确实保留了每个组内的行顺序。

【讨论】:

    【解决方案3】:

    为了保持秩序,您需要传递.groupby(..., sort=False)。在您的情况下,分组列已经排序,因此没有区别,但通常必须使用 sort=False 标志:

     df.groupby('A', sort=False).agg([np.mean, lambda x: x.iloc[1] ])
    

    【讨论】:

    • groupby 有一个 sort= 标志,但这与组本身的排序有关,与组内的观察无关。
    • 他们应该把它设为默认参数,考虑到它经常被使用
    • 具有讽刺意味的是,文档还说“通过关闭它来获得更好的性能。”。那么它应该是可选功能而不是默认功能的另一个原因。最重要的是,它会更改调用者可能意想不到的数据。
    【解决方案4】:

    Panda 的 0.19.1 文档说“groupby 保留每个组中行的顺序”,因此这是有保证的行为。

    http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html

    【讨论】:

      【解决方案5】:

      更简单:

        import pandas as pd
        pd.pivot_table(df,index='A',aggfunc=(np.mean))
      

      输出:

                  B    C
           A                
         group1  11.0  101
         group2  17.5  175
         group3  11.0  101
      

      【讨论】:

        【解决方案6】:

        查看此增强功能issue

        简短的回答是肯定的,groupby 将保留传入的顺序。您可以使用如下示例来证明这一点:

        In [20]: df.sort_index(ascending=False).groupby('A').agg([np.mean, lambda x: x.iloc[1] ])
        Out[20]: 
                   B             C         
                mean <lambda> mean <lambda>
        A                                  
        group1  11.0       10  101      100
        group2  17.5       10  175      100
        group3  11.0       10  101      100
        

        这不适用于重采样,但是因为它需要一个单调索引(它将与非单调索引一起使用,但会首先对其进行排序)。

        它们是 groupby 的 sort= 标志,但这与组本身的排序有关,而不是组内的观察。

        仅供参考:df.groupby('A').nth(1) 是获取组的第二个值的安全方法(因为如果组具有

        【讨论】:

        • 感谢您的澄清和问题链接!我最初以iloc 为例,因为我不知道如何将nth() 传递给agg() 调用(因为那时x 是一个系列)。除了作为 DataFrame 成员函数之外,还有其他方法可以调用 nth() 吗?
        • nth 仅在 groupby 上定义。你是什​​么意思'除了 DataFrame 成员函数'?
        • 我的意思是我不知道如何将nth() 作为列表中发送的函数之一传递给agg()。你不能做.agg([np.mean, nth]),或DataFrame.nth()lambda x: x.nth(2)。这就是导致我使用 iloc 的原因,尽管它会引发索引错误。最好的方法可能是不要尝试一步完成。先用nth()再用agg(),再合并。
        猜你喜欢
        • 1970-01-01
        • 2015-12-08
        • 2020-03-03
        • 1970-01-01
        • 2023-03-24
        • 2018-04-06
        • 2012-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多