Pandas Dataframe groupby 聚合函数和动态列的最大值和最小值之间的差异

Posted

技术标签:

【中文标题】Pandas Dataframe groupby 聚合函数和动态列的最大值和最小值之间的差异【英文标题】:Pandas Dataframe groupby aggregate functions and difference between max and min of a column on the fly 【发布时间】:2021-01-03 23:03:17 【问题描述】:
import pandas as pd

df = 'a': ['xxx', 'xxx','xxx','yyy','yyy','yyy'], 'start': [10000, 10500, 11000, 12000, 13000, 14000] 
df = pd.DataFrame(data=df)


df_new = df.groupby("a",as_index=True).agg(
            ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
            StartMin=pd.NamedAgg(column='start', aggfunc="min"),
            StartMax=pd.NamedAgg(column='start', aggfunc="max"),
            )

给予

>>>df_new
     ProcessiveGroupLength  StartMin  StartMax
a
xxx                      3     10000     11000
yyy                      3     12000     14000

如何在飞行中到达下方,因为我认为飞行中会更快。

>>>df_new
     ProcessiveGroupLength    Diff
a
xxx                      3      1000
yyy                      3      2000

以下代码给出以下错误消息:

Traceback(最近一次通话最后一次): 文件“”,第 5 行,在 TypeError: 不支持的操作数类型 -: 'str' 和 'str'

df_new = df.groupby("a").agg(
            ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),                
            Diff=pd.NamedAgg(column='start', aggfunc="max"-"min"),)

【问题讨论】:

您实际上会感到惊讶,但之后执行减法可能是您最高效的结果。这是因为通过添加另一个聚合器,您要求 pandas 为每个组找到两次最小值和最大值。一次用于 StartMin,一次用于 StartMax,然后在计算 Diff 时再进行 2 次。 @CameronRiddell 谢谢,。事实上,我想以最快速、最有效的方式找到差异。因此我删除了不必要的列。 【参考方案1】:

您的解决方案应该由 lambda 函数更改,但我认为如果有很多组或/和大型 DataFrame,这应该像第一个解决方案一样慢。

原因是优化了函数maxmin 以及Series 的向量减法。换句话说,如果不使用 lambda 函数,聚合会更快。

df_new = df.groupby("a").agg(
            ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
            Diff=pd.NamedAgg(column='start', aggfunc=lambda x: x.max() - x.min()),)

或者你可以使用numpy.ptp:

df_new = df.groupby("a").agg(
            ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
            Diff=pd.NamedAgg(column='start', aggfunc=np.ptp),)

print (df_new)
     ProcessiveGroupLength  Diff
a                               
xxx                      3  1000
yyy                      3  2000

性能:取决于数据,这里使用了 1M 行中的 1k 组:

np.random.seed(20)

N = 1000000
df = pd.DataFrame('a': np.random.randint(1000, size=N),
                   'start':np.random.randint(10000, size=N))
print (df)

In [229]: %%timeit
     ...: df_new = df.groupby("a",as_index=True).agg(
     ...:             ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
     ...:             StartMin=pd.NamedAgg(column='start', aggfunc="min"),
     ...:             StartMax=pd.NamedAgg(column='start', aggfunc="max"),
     ...:             ).assign(Diff = lambda x: x.pop('StartMax') - x.pop('StartMin'))
     ...:             
69 ms ± 728 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [230]: %%timeit
     ...: df_new = df.groupby("a").agg(
     ...:             ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
     ...:             Diff=pd.NamedAgg(column='start', aggfunc=lambda x: x.max() - x.min()),)
     ...:             
172 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [231]: %%timeit
     ...: df_new = df.groupby("a").agg(
     ...:             ProcessiveGroupLength=pd.NamedAgg(column='start', aggfunc="count"),
     ...:             Diff=pd.NamedAgg(column='start', aggfunc=np.ptp),)
     ...:             
171 ms ± 3.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

您的“assign”解决方案似乎比其他两个解决方案更好。谢谢。 为什么 lambda x: x.pop('StartMax') - x.pop('StartMin') 比 np.ptp 快? @burcak - 我猜在后台使用x.max() - x.min()) @burcak - 分配代替df_new['Diff'] = df_new.pop('StartMax') - df_new.pop('StartMin')pop 用于避免在下一步中删除列。

以上是关于Pandas Dataframe groupby 聚合函数和动态列的最大值和最小值之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

将 pandas.core.groupby.SeriesGroupBy 转换为 DataFrame

如何将pandas dataframe进行groupby操作后得到的数据结构转换为dataframe?

pandas将初始dataframe基于分组变量拆分为多个新的dataframe使用groupby函数tuple函数dict函数(splitting dataframe multiple)

Dataframe Pandas 聚合和/或 groupby

Python pandas dataframe groupby 选择列

Pandas DataFrame groupby,跨列计数和求和