Python Pandas:使用groupby()和agg()时顺序是否保留?

81 投票
6 回答
52282 浏览
提问于 2025-04-28 11:01

我经常使用 pandas 的 agg() 函数来对数据框中的每一列进行汇总统计。比如,下面这个例子展示了如何计算平均值和标准差:

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() 结合加权平均函数,所以我想确保传入函数的行顺序和原始数据框中的顺序是一致的。

有没有人知道,最好是通过文档或 pandas 源代码,是否可以保证这一点?

暂无标签

6 个回答

3

很遗憾,这个问题的答案是否定的。在过去几天里,我创建了一个用于不均匀分块的算法,但发现它无法保持顺序,因为使用了分组操作,这样每个分组都会生成子框架,而每个框架的关键字都是分组输入。因此,最后的结果是:

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

因为它使用了字典,所以你会失去原来的顺序。

如果你在之后进行排序,正如上面提到的,我刚刚在一个大数据集上测试过,这样的计算复杂度是O(n log n)。

不过,我发现如果你有有序的时间序列数据,并且想要保持顺序,最好是把排序的列变成一个列表,然后创建一个计数器来记录每个时间序列中的第一个项目。这样计算的复杂度是O(n)。

所以,简单来说,如果你使用的是相对较小的数据集,上面提到的解决方案是合理的,但如果你使用的是大数据集,就需要考虑避免使用分组和排序。相反,可以使用:list(df['myColumnToOrderBy']),然后对它进行迭代。

5

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

这个接口接受一个叫“SORT”的参数。

关于SORT参数的说明是这样的:

sort : 布尔值,默认是True 排序分组的键。如果把这个关掉,性能会更好。需要注意的是,这个设置不会影响每个组内观察值的顺序。Groupby会保持每个组内行的顺序

所以,很明显“Groupby”确实会保持每个组内行的顺序。

30

Panda的0.19.1文档说“分组操作会保留每个组内行的顺序”,所以这是一个可以保证的行为。

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

52

为了保持顺序,你需要使用 .groupby(..., sort=False) 这个设置。在你的情况中,分组的那一列已经排好序了,所以用不用这个设置都没什么区别,但通常情况下,大家都应该加上 sort=False 这个选项。

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

可以查看这个增强功能的问题

简单来说,使用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

不过,resample就不一样了,它需要一个单调的索引(虽然它可以在非单调索引下工作,但会先对数据进行排序)。

groupby有一个sort=的选项,但这个是用来控制组的排序,而不是组内数据的排序。

顺便提一下,df.groupby('A').nth(1)是获取某个组第二个值的安全方法(因为你上面的方法如果组里元素少于2个就会出错)。

撰写回答