Python 熊猫在群体中移动缓慢

Python 熊猫在群体中移动缓慢,python,pandas,Python,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
非常棒。很快

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
但是当我在
groupby
之后执行
tshift
时,速度会慢很多:

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.
鉴于,如果我们增加A组和B组的数量:

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

我感到惊讶的是,随着团队数量的增加,增长速度也在放缓!有没有更聪明的方法可以做到这一点?

tshift
需要一个freq参数用于此用法(因为一旦分组,freq可能是不规则的),因此
df.groupby('a')。tshift(-1)
返回一个空帧(它为每个组提升,也会降低速度)

除此之外,这个问题也在等待shift(和tshift)的cythonized实现。这将使这与总和,这是细胞化。欢迎捐款

使用第二个数据集(较大的组),您可以执行以下操作:

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倍。这(和缓存)可能是加快分组T换档的第一步。

谢谢,杰夫!请参阅下面我的更新。我的实际代码显示了频率;我只是错误地把它放在了示例中。看起来我的实际问题是团队的数量?n_A和n_B实际上分别为2k-500k和121。好吧,这之所以慢,是因为单个操作最终会执行
时间戳+偏移量
(例如,添加特定的时间戳和偏移量(此处为负))。这是非常具体的语义,当添加月/年以使事物正确着陆时,诸如此类。就其本身而言,这种操作是好的。然而,这是重复多次。所以这可以被缓存以大大加快速度。将创建一个问题来跟踪此问题。此外,您实际上正在执行一种完全不同类型的操作,即
.sum()
,这是一种减少。你在这里做的本质上是一个转变,这是重复的。谢谢杰夫!听起来,如果我放弃日期时间,只使用数字,可能会有所改善。目前我只记录了几年。几年来,我一直尝试使用float并进行
.transform(lambda x:x-5)
,但这也导致了这种增长放缓。尽管不可否认的较少:对于我上面的两个示例,使用x13和x132。还有更好的方法吗?旁注:在实际用例中,一些日期是不存在的。这就是我喜欢tshift的原因;如果指数是1975年,1980年,2005年,我会以1970年,1975年,2000年结束。目前,使用数字和仅仅计算x-5就可以了,但是如果我用月/日切换到正确的日期,这将是一个更大的问题。
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