为什么cumcount比它的.apply()等效更快?

时间:2018-03-07 10:12:05

标签: python pandas

假设我们有这个简单的数据框:

dd = pd.DataFrame({'ID':np.random.randint(100000, size=50000000)})

为什么

%%time
res1 = dd.groupby('ID').cumcount()

比以下快得多:

%%time
res2 = dd.groupby('ID')['ID'].apply(lambda x: pd.Series(np.arange(len(x)), x.index))

cumcount的文档声称这些实现是等效的。我认为,只有在结果中。 .apply()也消耗更多的记忆,也许不出所料。

这将帮助我编写更好的代码来处理我的pandas数据帧。到目前为止,应用自己的函数的唯一方法是通过上面的.apply()

2 个答案:

答案 0 :(得分:2)

在大熊猫中使用.sum().mean().cumsum()等方法时,这些操作会完全优化(通过cython / numpy)。 这些方法比lambda等效方法快得多,因为使用lambda时,评估是在Python中完成的。

因此,一般来说,您应尽量使用尽可能多的pandas方法,即使以计算中有更多中间步骤为代价。

这是一个有趣的例子,可以帮助澄清:

import numpy as np
import pandas as pd

test = pd.DataFrame(np.random.randn(10, 2), columns=['A', 'B'])
test['Cond_1'] = ['A']*5 + ['B']*5
test['Cond_2'] = ['a', 'b']*5

当执行.sum()pandas正在使用C例程(非常快)时,未定义字符串sum,因此您只需返回数字列。

test.groupby(by='Cond_1').sum()

Out[5]: 
            A         B
Cond_1                    
A       1.620708 -1.609602
B       0.146317 -1.080326

如果你使用lambda,pandas将使用纯python,你确实可以对字符串求和!

test.groupby(by='Cond_1').apply(lambda x: x.sum())

Out[6]: 
             A        B     Cond_1 Cond_2
Cond_1                                  
A       1.620708 -1.609602  AAAAA  ababa
B       0.146317 -1.080326  BBBBB  babab

答案 1 :(得分:1)

我认为你的问题可以改写为“为什么适用这么慢?”。对此的答案是因为,apply从未意味着快速。

apply与循环标准之间的唯一区别在于,使用apply,您无法看到循环。是的,这意味着apply并不比顺序迭代每个组更好,并且无论你传递给它的功能如何。 apply是一个便利函数(普通的for循环有时甚至可能更快),所以要像瘟疫一样避免它,特别是当有更快的替代方案时。

另一方面,

groupby.cumcount更具性能,因为每个组的操作都是向量化的。