如果 dtype 是类别,pivot_table 需要更多内存(MemoryError)

Fib*_*eap 4 python dataframe python-3.x pandas

我对 pandas(pandas==0.23.1) 有以下奇怪的错误:

import pandas as pd
df = pd.DataFrame({'t1': ["a","b","c"]*10000, 't2': ["x","y","z"]*10000, 'i1': list(range(5000))*6, 'i2': list(range(5000))*6, 'dummy':0})
# works fast with less memory
piv = df.pivot_table(values='dummy', index=['i1','i2'], columns=['t1','t2'])

d2 = df.copy()
d2.t1 = d2.t1.astype('category')
d2.t2 = d2.t2.astype('category')

# needs > 20GB of memory and takes for ever
piv2 = d2.pivot_table(values='dummy', index=['i1','i2'], columns=['t1','t2'])
Run Code Online (Sandbox Code Playgroud)

我想知道这是否是预期的并且我做错了什么,或者这是否是 pandas 中的错误。dtype categoryfor应该str不是很透明(对于这个用例)?

jpp*_*jpp 5

这不是一个错误。现在正在pandas.pivot_table计算石斑鱼类别的笛卡尔积。

这是已知的有意行为。在 Pandas v0.23.0 中,我们看到了observed参数的引入pandas.groupby。设置observed=True仅包括观察到的组合;这是False默认的。这一论点目前尚未推广到相关方法,例如pandas.pivot_table. 在我看来,应该是这样。

但现在让我们看看这意味着什么。print我们可以使用一个示例数据框,看看我们得到结果时会发生什么。

设置

我们使数据框变得更小:

import pandas as pd

n = 10

df = pd.DataFrame({'t1': ["a","b","c"]*n, 't2': ["x","y","z"]*n,
                   'i1': list(range(int(n/2)))*6, 'i2': list(range(int(n/2)))*6,
                   'dummy':0})
Run Code Online (Sandbox Code Playgroud)

没有类别

这可能就是您正在寻找的。未观察到的类别组合不会在数据透视表中表示。

piv = df.pivot_table(values='dummy', index=['i1','i2'], columns=['t1','t2'])
print(piv)

t1     a  b  c
t2     x  y  z
i1 i2         
0  0   0  0  0
1  1   0  0  0
2  2   0  0  0
3  3   0  0  0
4  4   0  0  0
Run Code Online (Sandbox Code Playgroud)

有类别

对于类别,所有类别组合,甚至是未观察到的组合,都会在结果中得到考虑。这在计算上是昂贵的并且需要内存。此外,数据帧主要由未观察到的组合组成NaN。这可能不是你想要的。

更新:您现在可以将observed参数设置为True仅显示分类石斑鱼的观察值。

d2 = df.copy()
d2.t1 = d2.t1.astype('category')
d2.t2 = d2.t2.astype('category')

piv2 = d2.pivot_table(values='dummy', index=['i1','i2'], columns=['t1','t2'])
print(piv2)

t1       a           b            c         
t2       x   y   z   x    y   z   x   y    z
i1 i2                                       
0  0   0.0 NaN NaN NaN  0.0 NaN NaN NaN  0.0
   1   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   2   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   3   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   4   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
1  0   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   1   0.0 NaN NaN NaN  0.0 NaN NaN NaN  0.0
   2   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   3   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   4   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
2  0   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   1   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   2   0.0 NaN NaN NaN  0.0 NaN NaN NaN  0.0
   3   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   4   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
3  0   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   1   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   2   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   3   0.0 NaN NaN NaN  0.0 NaN NaN NaN  0.0
   4   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
4  0   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   1   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   2   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   3   NaN NaN NaN NaN  NaN NaN NaN NaN  NaN
   4   0.0 NaN NaN NaN  0.0 NaN NaN NaN  0.0
Run Code Online (Sandbox Code Playgroud)

  • 值得庆幸的是,pivot_table 现在包含一个“观察到的”参数(请参阅https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.pivot_table.html)。将其设置为 True 可以让我快速创建带有分类列的数据透视表。当它设置为 False 时,我的计算机在尝试创建表时使用了超过 50 GB 的内存。 (2认同)