Python Pandas:使用groupby()和agg()时顺序是否保留?
我经常使用 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 个回答
很遗憾,这个问题的答案是否定的。在过去几天里,我创建了一个用于不均匀分块的算法,但发现它无法保持顺序,因为使用了分组操作,这样每个分组都会生成子框架,而每个框架的关键字都是分组输入。因此,最后的结果是:
allSubFrames = df.groupby("myColumnToOrderBy")
for orderKey, individualSubFrame in allSubFrames:
do something...
因为它使用了字典,所以你会失去原来的顺序。
如果你在之后进行排序,正如上面提到的,我刚刚在一个大数据集上测试过,这样的计算复杂度是O(n log n)。
不过,我发现如果你有有序的时间序列数据,并且想要保持顺序,最好是把排序的列变成一个列表,然后创建一个计数器来记录每个时间序列中的第一个项目。这样计算的复杂度是O(n)。
所以,简单来说,如果你使用的是相对较小的数据集,上面提到的解决方案是合理的,但如果你使用的是大数据集,就需要考虑避免使用分组和排序。相反,可以使用:list(df['myColumnToOrderBy'])
,然后对它进行迭代。
参考链接: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html
这个接口接受一个叫“SORT”的参数。
关于SORT参数的说明是这样的:
sort : 布尔值,默认是True 排序分组的键。如果把这个关掉,性能会更好。需要注意的是,这个设置不会影响每个组内观察值的顺序。Groupby会保持每个组内行的顺序。
所以,很明显“Groupby”确实会保持每个组内行的顺序。
Panda的0.19.1文档说“分组操作会保留每个组内行的顺序”,所以这是一个可以保证的行为。
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html
为了保持顺序,你需要使用 .groupby(..., sort=False)
这个设置。在你的情况中,分组的那一列已经排好序了,所以用不用这个设置都没什么区别,但通常情况下,大家都应该加上 sort=False
这个选项。
df.groupby('A', sort=False).agg([np.mean, lambda x: x.iloc[1] ])
可以查看这个增强功能的问题
简单来说,使用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个就会出错)。