python Pandas分组:有效链接多个功能

cgvd09ve  于 2023-01-04  发布在  Python
关注(0)|答案(2)|浏览(123)

我需要对一个DataFrame进行分组,并在每个分组上应用几个链接函数。
我的问题与pandas - Groupby two functions中的基本相同:在每组上依次应用cumsumshift
关于如何获得正确的结果,有一些答案,但它们似乎有次优的性能。我的具体问题是:是否有比我下面描述的方法更有效的方法?
首先是一些大型测试数据:

from string import ascii_lowercase

import numpy as np
import pandas as pd

n = 100_000_000
np.random.seed(0)
df = pd.DataFrame(
    {
        "x": np.random.choice(np.array([*ascii_lowercase]), size=n),
        "y": np.random.normal(size=n),
    }
)

以下是每个功能的性能:

%timeit df.groupby("x")["y"].cumsum()
4.65 s ± 71 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df.groupby("x")["y"].shift()
5.29 s ± 54.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

一个基本的解决方案是分组两次,这似乎不是最佳的,因为分组是整个运行时的一大部分,应该只进行一次。

%timeit df.groupby("x")["y"].cumsum().groupby(df["x"]).shift()
10.1 s ± 63.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

上述问题的公认答案建议使用带有自定义函数的apply来避免这个问题,但由于某些原因,它实际上比以前的解决方案性能差得多。

def cumsum_shift(s):
    return s.cumsum().shift()

%timeit df.groupby("x")["y"].apply(cumsum_shift)
27.8 s ± 858 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

你知道如何优化这段代码吗?特别是在我想链接两个以上函数的情况下,性能的提高会变得非常显著。

rkue9o1l

rkue9o1l1#

如果有帮助,请告诉我,几周前我也有同样的问题。
我通过拆分代码并创建一个包含组信息的单独groupby对象来解决这个问题。

# creating groupby object
g = df.groupby('x')['y']

%timeit g.cumsum()
592 ms ± 8.67 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit g.shift()
1.7 s ± 8.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
e0bqpujr

e0bqpujr2#

我建议尝试一下transform而不是apply
试试这个:

%timeit df.groupby("x")["y"].transform(np.cumsum).transform(lambda x: x.shift())

或者,也可以尝试使用

from toolz import pipe

%timeit df.groupby("x").pipe(lambda g: g["y"].cumsum().shift())

我非常肯定pipe比apply或transform更高效。请告诉我们它是否工作正常

相关问题