Pandas DataFrame - 在列dos =='category'的列上聚合会导致性能下降

时间:2017-12-31 13:41:16

标签: python-2.7 pandas dataframe pandas-groupby numpy-dtype

我使用内存使用率很高的大数据帧,我读到如果我在重复值列上更改dtype,我可以节省大量内存。

我尝试过它确实将内存使用率降低了25%,但后来我遇到了一个我无法理解的性能缓慢。

我在dtype'category'列上进行分组聚合,在我更改dtype之前需要大约1秒钟,在更改之后大约需要1分钟。

此代码演示了因子2的性能下降:

import pandas as pd
import random

animals = ['Dog', 'Cat']
days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday','Saturday']

columns_dict = {'animals': [],
                'days': []}

for i in range(1000000):
    columns_dict['animals'].append(animals[random.randint(0, len(animals)-1)])
    columns_dict['days'].append(days[random.randint(0, len(days)-1)])

# df without 'category' dtype
df = pd.DataFrame(columns_dict)

df.info(memory_usage='deep') # will result in memory usage of 95.5 MB

%timeit -n100 df.groupby('days').agg({'animals': 'first'})
# will result in: 100 loops, best of 3: 54.2 ms per loop

# df with 'category' dtype
df2 = df.copy()
df2['animals'] = df2['animals'].astype('category')

df2.info(memory_usage='deep') # will result in memory usage of 50.7 MB

%timeit -n100 df2.groupby('days').agg({'animals': 'first'})
# will result in: 100 loops, best of 3: 111 ms per loop

我试图理解的是这种缓慢的原因是什么,以及是否有办法克服它。

谢谢!

1 个答案:

答案 0 :(得分:7)

我不确定这种减速的来源,但一种解决方法是直接存储类别代码:

df3 = df.copy()
animals = pd.Categorical(df['animals'])
df3['animals'] = animals.codes
df3.groupby('days').agg({'animals': 'first'}).apply(lambda code: animals.categories[code])

这不是最干净的解决方案,因为它需要外部元数据,但它可以实现内存效率和您正在寻找的计算速度。挖掘Pandas在内部做的事情会导致分类的减速,这将会很有趣。

编辑:我跟踪了为什么会发生这种情况......作为first()聚合,pandas calls np.asarray() on the column的一部分。在分类列的情况下,这最终会将列转换回非分类,从而导致不必要的开销。修复这个将是对pandas包的有用贡献!