假设我们有这个简单的数据框:
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()
。
答案 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
更具性能,因为每个组的操作都是向量化的。