如何使用 groupbys 成为更快的熊猫

How to be a faster Panda with groupbys

我有一个包含 1.5 亿行的 Pandas 数据框。其中大约有 100 万个组,我想对其进行一些非常简单的计算。例如,我想采用一些现有的列 'A' 并创建一个新列 'A_Percentile',将 'A' 的值表示为组内的百分位等级。这是一个执行此操作的小函数:

from scipy.stats import percentileofscore

def rankify(column_name,data=my_data_frame):
    f = lambda x: [percentileofscore(x, y) for y in x]
    data[column_name+'_Percentile'] = data.groupby(['Group_variable_1',
                                               'Group_variable_2'])[column_name].transform(f)
    return

那么你可以这样称呼它:

rankify('Column_to_Rank', my_data_frame)

并等待...相当长的时间。

我可以做一些明显的事情来加快速度(例如,我确信有一种方法可以矢量化 [percentileofscore(x, y) for y in x])。但是,我觉得我可以使用一些 Pandas 技巧来极大地加快速度。我可以用 groupby 逻辑做些什么吗?我考虑过将其拆分并并行化,但是 1. 我不确定这样做的好方法和 2. 写出数据和读取结果的通信时间似乎需要几乎一样长的时间(也许我认为是因为第 1 点)。

正如您可能知道的那样,groupby 操作的速度可能会有很大差异——尤其是当组的数量变多时。这是一个非常简单的替代方法,它在我尝试过的一些测试数据集上要快得多(快 2 倍到 40 倍)。如果你能避免用户编写的函数(与 groupby 结合)并坚持使用内置函数(通常是 cythonized)通常会更快:

In [163]: %timeit rankify('x',df)
1 loops, best of 3: 7.38 s per loop

In [164]: def rankify2(column_name,data):
     ...:     r1 = data.groupby('grp')[column_name].rank()
     ...:     r2 = data.groupby('grp')[column_name].transform('count')
     ...:     data[column_name+'_Percentile2'] = 100. * r1 / r2 

In [165]: %timeit rankify2('x',df)
10 loops, best of 3: 178 ms per loop

请注意,与 percentileofscore() 相比,我的方法给出的结果略有不同(例如 10e-15 的差异)。因此,如果您使用 x == y 测试结果,大多数结果为 True,但有些为 False,但 x.round() == y.round() 将通过。

对于上面的结果,这是我的测试数据集(对于我尝试过的其他情况,差异较小但总是 2 倍或更好的加速):

df = pd.DataFrame( { "grp" : np.repeat( np.arange(1000), 100 ),
                     "x"   : np.random.randn(100000)           } )

如果您愿意,我相信您可以做得更好。实际上,您在这里需要做的就是排序和排名。我怀疑我采用的基本方法将是一个很好的方法,但如果你在 numpy 或 numba 中完成了部分或全部,你可能会加快速度。此外,您也许可以使用一些 pandas 索引技巧来加快速度。