首页 > 解决方案 > pandas.unique() 奇怪的内存消耗

问题描述

在分析我的算法的内存消耗时,我很惊讶有时对于较小的输入需要更多的内存。

这一切都归结为以下用法pandas.unique()

import numpy as np
import pandas as pd
import sys

N=int(sys.argv[1])

a=np.arange(N, dtype=np.int64)
b=pd.unique(a)

N=6*10^7它需要3.7GB峰值内存,但需要N=8*10^7"only" 3GB

扫描不同的输入大小会产生下图:

在此处输入图像描述

出于好奇和自我教育:如何解释 , 周围的违反直觉的行为(即更多的内存用于更小的输入大小) ?N=5*10^7N=1.3*10^7


以下是在 Linux 上生成内存消耗图的脚本:

pandas_unique_test.py

import numpy as np
import pandas as pd
import sys

N=int(sys.argv[1])    
a=np.arange(N, dtype=np.int64)
b=pd.unique(a)

show_memory.py

import sys
import matplotlib.pyplot as plt   
ns=[]
mems=[]
for line in sys.stdin.readlines():
    n,mem = map(int, line.strip().split(" "))
    ns.append(n)
    mems.append(mem)
plt.plot(ns, mems, label='peak-memory')
plt.xlabel('n')
plt.ylabel('peak memory in KB')
ymin, ymax = plt.ylim()
plt.ylim(0,ymax)
plt.legend()
plt.show()

run_perf_test.sh

WRAPPER="/usr/bin/time -f%M" #peak memory in Kb
N=1000000
while [ $N -lt 100000000 ]
do
   printf "$N "
   $WRAPPER python pandas_unique_test.py $N
   N=`expr $N + 1000000`
done 

现在:

sh run_perf_tests.sh  2>&1 | python show_memory.py

标签: pythonalgorithmperformancepandas

解决方案


让我们来看看...

pandas.unique说它是“基于哈希表的唯一”。

它调用此函数来为您的数据获取正确的哈希表实现,即htable.Int64HashTable.

哈希表初始化为size_hint= 值向量的长度。这意味着kh_resize_DTYPE(table, size_hint)被调用。

这些函数khash.h.

它似乎为(size_hint >> 5) * 4 + (size_hint) * 8 * 2存储桶分配了字节的内存(可能更多,也可能更少,我可能会离开这里)。

然后,HashTable.unique()被调用。

它分配一个 empty ,从128Int64Vector开始,每当它们被填充时,它们的大小似乎会增加四倍

然后它会遍历你的值,确定它们是否在哈希表中;如果没有,它们将被添加到哈希表和向量中。(这是向量可能增长的地方;由于大小提示,哈希表不需要增长。)

最后,使 NumPyndarray指向向量。

所以,呃,我认为你看到向量大小在某些阈值处翻了两番(如果我的深夜数学站得住,那应该是,

>>> [2 ** (2 * i - 1) for i in range(4, 20)]
[
    128,
    512,
    2048,
    8192,
    32768,
    131072,
    524288,
    2097152,
    8388608,
    33554432,
    134217728,
    536870912,
    2147483648,
    8589934592,
    34359738368,
    137438953472,
    ...,
]

希望这对事情有所启发:)


推荐阅读