熊猫tshift成群慢

时间:2014-10-10 09:14:04

标签: python pandas

使用Pandas tshift非常棒。这很快!

df = pd.DataFrame(index=pd.date_range(pd.datetime(1970,1,1),pd.datetime(1970,2,1)))
df['data']=.5
%timeit df.sum()
#10000 loops, best of 3: 162 µs per loop 
%timeit df.tshift(-1)
#1000 loops, best of 3: 307 µs per loop #x2 slower

但是当我在tshift之后groupby进行df = pd.DataFrame(index=pd.date_range(pd.datetime(1970,1,1),pd.datetime(1970,2,1))) df['data']=.5 df['A'] = randint(0,2,len(df.index)) %timeit df.groupby('A').sum() #100 loops, best of 3: 2.72 ms per loop %timeit df.groupby('A').tshift(-1) #10 loops, best of 3: 16 ms per loop #x6 slower! 时,它会放慢速度:

tshift

为什么n_A = 50 n_B = 5 index = pd.MultiIndex.from_product([arange(n_A), arange(n_B), pd.date_range(pd.datetime(1975,1,1), pd.datetime(2010,1,1), freq='5AS')], names=['A', 'B', 'Year']) df = pd.DataFrame(index=index) df['data']=.5 %timeit df.reset_index(['A','B']).groupby(['A','B']).sum() #100 loops, best of 3: 4.34 ms per loop %timeit df.reset_index(['A','B']).groupby(['A','B']).tshift(-1, freq='5AS') #10 loops, best of 3: 198 ms per loop # X44 slowdown. 在进行分组时会这么慢?有没有办法更快?

更新

我的实际使用案例更接近以下代码。我看到减速乘数的大小取决于组的数量。

n_A = 500
n_B = 50
...
%timeit df.reset_index(['A','B']).groupby(['A','B']).sum()
#10 loops, best of 3: 35.8 ms per loop
%timeit df.reset_index(['A','B']).groupby(['A','B']).tshift(-1, freq='5AS')
#1 loops, best of 3: 20.3 s per loop # X567 slowdown

然而,如果我们增加A和B组的数量:

{{1}}

我感到惊讶的是,随着团队人数的增加,经济增长放缓!有更聪明的方法吗?

1 个答案:

答案 0 :(得分:5)

tshift需要一个freq参数用于此用法(因为freq在分组时可能并且通常不常规),因此df.groupby('A').tshift(-1)返回一个空帧(它为每个组提升,减慢它同样)。

In [44]: %timeit df.groupby('A').tshift(-1,'D')
100 loops, best of 3: 3.57 ms per loop

In [45]: %timeit df.groupby('A').sum()
1000 loops, best of 3: 1.02 ms per loop

除此之外,这个问题here正在等待shift(和tshift)的cythonized实现。这将使得与sum相提并论,这是cython化的。欢迎捐款!

使用您的第二个数据集(更大的组),您可以这样做:

In [59]: def f(df):
   ....:     x = df.reset_index()
   ....:     x['Year_ts'] = pd.DatetimeIndex(x['Year'])-pd.offsets.YearBegin(5)
   ....:     return x.drop(['Year'],axis=1).rename(columns={'Year_ts' : 'Year'}).set_index(['A','B','Year'])
   ....: 

In [60]: result = df.reset_index(['A','B']).groupby(['A','B']).tshift(-1,'5AS')

In [61]: %timeit df.reset_index(['A','B']).groupby(['A','B']).tshift(-1,'5AS')
1 loops, best of 3: 10.8 s per loop

In [62]: result2 = f(df)

In [63]: %timeit f(df)
1 loops, best of 3: 2.51 s per loop

In [64]: result.equals(result2)
Out[64]: True

因此,在groupby之外进行日期减法使得速度提高约4倍。而且(和缓存)是使分组tshift更快的第一步。