Python 如何通过groupbys成为更快的熊猫

Python 如何通过groupbys成为更快的熊猫,python,performance,pandas,bigdata,dataframe,Python,Performance,Pandas,Bigdata,Dataframe,我有一个有1.5亿行的熊猫数据帧。其中大约有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

我有一个有1.5亿行的熊猫数据帧。其中大约有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)
等待…相当长的一段时间


我可以做一些明显的事情来加快速度(例如,我确信有一种方法可以向量化
[x中y的百分位数(x,y)]
)。然而,我有一种感觉,那就是我可以做一些小动作来大大加快速度。我可以用
groupby
逻辑做些什么吗?我想把它拆开并并行化,但是1。我不确定有没有一个好方法来做这件事。写出数据和读取结果所需的通信时间似乎与第1点差不多长(也许我认为这是因为第1点)。

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

请注意,与
百分位分数()相比,我的方法给出的结果稍有不同(比如
10e-15
)。因此,如果使用
x==y
测试结果,大多数结果是正确的,但有些结果是错误的,但是
x.round()==y.round()
将通过测试

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


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

谢谢!事实上,这是非常快的。关键的建议似乎是尽可能使用内置函数。1.还有其他技巧/原则吗?2.我发现浏览groupbys的内置函数是一件棘手且令人困惑的事情。关于groupbys的所有内置功能,哪里有好的文档?除了尽可能坚持使用内置功能和使用最新版本的pandas外,我没有其他一般建议。对我来说,这主要是反复试验,再加上你可以用
rank
count
做很多事情,这两种方法都非常快。如果浏览发行说明中的性能部分,您可以看到groupby的各种功能是何时被循环化的。您还可以搜索“groupby slow”之类的内容,尤其是在与“大数据集”或“大量组”的组合中。
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
df = pd.DataFrame( { "grp" : np.repeat( np.arange(1000), 100 ),
                     "x"   : np.random.randn(100000)           } )