python - Pandas 成群移动缓慢

标签 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

但是当我在 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 参数来实现此用法(因为一旦分组,频率可能并且通常不规则),因此 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 相当,它是 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 倍。这(和缓存)可能是使分组 tshift 更快的第一步。

关于python - Pandas 成群移动缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26295861/

相关文章:

python - 将对数曲线拟合到数据点并在 numpy 中外推

python - 如何合并两个具有不同结束日期的时间序列数据框并保留较长的结束日期

python - Pandas 根据上一个可用值和下一个可用值填充 NaN

python - Pandas : Merge two Dataframes on a column, 但仅保留不同列的数据

python - 基于 Pandas 中的对称矩阵从系列中删除重复项

python - 使用内部连接连接两个数据框

python - 根据 csv 文件创建的列表将文件从一个目录复制到另一个目录

python - 我是否检查过该列表的每个连续子集?

python - 无法序列化org.apache.hadoop.io.DoubleWritable类-MongoDB Hadoop Connector + Spark + Python

python - “bool”对象不可调用