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

Posted

技术标签:

【中文标题】Pandas DataFrame - 在 whos dtype==\'category\' 列上聚合会导致性能下降【英文标题】:Pandas DataFrame - Aggregate on column whos dtype=='category' leads to slow performancePandas DataFrame - 在 whos dtype=='category' 列上聚合会导致性能下降 【发布时间】:2018-06-11 02:17:43 【问题描述】:

我使用具有高内存使用率的大数据帧,我读到如果我更改重复值列上的 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

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

谢谢!

【问题讨论】:

我在分类列和 group_by 操作方面遇到了完全相同的问题。请参阅我最近在SO question 上的帖子。将 dtype 列从类别重置回对象导致内存使用增加,但让我恢复更重要的运行时间。此外,保留类别列也减慢了我的多处理代码,因此我结束将所有类别列更改为对象。这不是您要寻找的答案,但它证实了您的经验。 【参考方案1】:

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

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 包的有益贡献!

【讨论】:

是的,因此是“解决方法”,“不是最干净的解决方案”,以及“解决这个问题将对 pandas 包做出有用的贡献”。

以上是关于Pandas DataFrame - 在 whos dtype=='category' 列上聚合会导致性能下降的主要内容,如果未能解决你的问题,请参考以下文章

pandas中dataframe索引排序实战:pandas中dataframe索引降序排序pandas中dataframe索引升序排序

pandas.dataframe怎么把列变成索引

pandas DataFrame和Series

如何在 Pandas 中遍历 DataFrame 中的行

如何在 Pandas 中遍历 DataFrame 中的行

pandas:在 MultiIndex DataFrame 上复制/广播单索引 DataFrame:操作方法和内存效率