内存使用,使用Dict填充Pandas DataFrame与使用键和值列表

时间:2016-07-29 22:30:40

标签: python performance list pandas dictionary

我正在创建一个读取二进制文件并返回可用于初始化@Component({ selector: 'registry_form', template: ' <label for="name">name {{model}}</label> <input [(ngModel)]="model" required > ', styleUrls: [...], directives: [...] }) export class RegistryFormComponent { @Input() model; } 的数据的包,我现在想知道是否最好返回DataFrame或两个列表(一个持有钥匙和持有价值的钥匙)。

我正在制作的软件包不应该完全依赖于dict对象,这就是为什么我的软件包当前将数据输出为DataFrame(为了便于访问)。如果可以节省一些内存和速度(这对我的应用程序至关重要,因为我处理数百万个数据点),我想输出密钥和值列表。然后,这些迭代将用于初始化dict

这是一个简单的例子:

DataFrame

据我了解,In [1]: d = {(1,1,1): '111', ...: (2,2,2): '222', ...: (3,3,3): '333', ...: (4,4,4): '444'} In [2]: keyslist=[(1,1,1),(2,2,2),(3,3,3),(4,4,4)] In [3]: valslist=['111','222','333','444'] In [4]: import pandas as pd In [5]: dfdict=pd.DataFrame(d.values(), index=pd.MultiIndex.from_tuples(d.keys(), names=['a','b','c'])) In [6]: dfdict Out[6]: 0 a b c 3 3 3 333 2 2 2 222 1 1 1 111 4 4 4 444 In [7]: dflist=pd.DataFrame(valslist, index=pd.MultiIndex.from_tuples(keyslist, names=['a','b','c'])) In [8]: dfpair Out[8]: 0 a b c 1 1 1 111 2 2 2 222 3 3 3 333 4 4 4 444 d.values()正在创建新的 副本 数据。如果我们忽略a d.keys()需要更多内存然后使用dict这一事实,使用listd.values()会导致更多内存使用,那么d.keys()对实现?

2 个答案:

答案 0 :(得分:3)

我对1M行进行了内存分析。获胜的结构是对每个数字索引使用array.array和字符串列表(147MB数据和310MB转换为pandas)。

根据Python手册

  

数组是序列类型,其行为与列表非常相似,除此之外   存储在其中的对象类型受到约束。

他们甚至有附加方法,并且很可能具有非常快的追加速度。

第二位是两个单独的列表。 (308MB和450MB)

另外两个选项,使用dict并使用带有四元组的列表,是最糟糕的。字典:339MB,524MB。清单四:308MB,514MB。

以下是array.array:

的用法
In [1]: from array import array
In [2]: import gc
In [3]: import pandas as pd
In [4]: %load_ext memory_profiler
In [5]: a1=array("l",range(1000000))
In [6]: a2=array("l",range(1000000))
In [7]: a3=array("l",range(1000000))
In [8]: b=[str(x*111) for x in list(range(1000000))]
In [9]: gc.collect()
Out[9]: 0
In [10]: %memit a1,a2,a3,b
peak memory: 147.64 MiB, increment: 0.32 MiB
In [11]: %memit dfpair=pd.DataFrame(b,  index=pd.MultiIndex.from_arrays([a1,a2,a3], names=['a','b','c']))
peak memory: 310.60 MiB, increment: 162.91 MiB

以下是代码的其余部分(很长):

四元组列表:

In [1]: import gc
In [2]: import pandas as pd
In [3]: %load_ext memory_profiler
In [4]: a=list(zip(list(range(1000000)),list(range(1000000)),list(range(1000000))))
In [5]: b=[str(x*111) for x in list(range(1000000))]
In [6]: d2=[x+(b[i],) for i,x in enumerate(a)]
In [7]: del a
In [8]: del b
In [9]: gc.collect()
Out[9]: 0
In [10]: %memit d2
peak memory: 308.40 MiB, increment: 0.28 MiB
In [11]: %memit df = pd.DataFrame(d2, columns=['a','b','c','d']).set_index(['a','b','c'])
peak memory: 514.21 MiB, increment: 205.80 MiB

字典:

In [1]: import gc
In [2]: import pandas as pd
In [3]: %load_ext memory_profiler
In [4]: a=list(zip(list(range(1000000)),list(range(1000000)),list(range(1000000))))
In [5]: b=[str(x*111) for x in list(range(1000000))]
In [6]: d = dict(zip(a, b))
In [7]: del a
In [8]: del b
In [9]: gc.collect()
Out[9]: 0
In [10]: %memit d
peak memory: 339.14 MiB, increment: 0.23 MiB
In [11]: %memit dfdict=pd.DataFrame(list(d.values()),  index=pd.MultiIndex.from_tuples(d.keys(), names=['a','b','c']))
peak memory: 524.10 MiB, increment: 184.95 MiB

两个阵列:

In [1]: import gc
In [2]: import pandas as pd
In [3]: %load_ext memory_profiler
In [4]: a=list(zip(list(range(1000000)),list(range(1000000)),list(range(1000000))))
In [5]: b=[str(x*111) for x in list(range(1000000))]
In [6]: gc.collect()
Out[6]: 0
In [7]: %memit a,b
peak memory: 307.75 MiB, increment: 0.19 MiB
In [8]: %memit dfpair=pd.DataFrame(b,  index=pd.MultiIndex.from_tuples(a, names=['a','b','c']))
peak memory: 459.94 MiB, increment: 152.19 MiB

答案 1 :(得分:0)

以下是使用memory_profiler的基准:

Filename: testdict.py

Line #    Mem usage    Increment   Line Contents
================================================
     4     66.2 MiB      0.0 MiB   @profile
     5                             def testdict():
     6
     7     66.2 MiB      0.0 MiB        d = {}
     8
     9    260.6 MiB    194.3 MiB        for i in xrange(0,1000000):
    10    260.6 MiB      0.0 MiB                d[(i,i,i)]=str(i)*3
    11
    12    400.2 MiB    139.6 MiB        dfdict=pd.DataFrame(d.values(),  index=
pd.MultiIndex.from_tuples(d.keys(), names=['a','b','c']))

Filename: testlist.py

Line #    Mem usage    Increment   Line Contents
================================================
     4     66.5 MiB      0.0 MiB   @profile
     5                             def testlist():
     6
     7     66.5 MiB      0.0 MiB        keyslist=[]
     8     66.5 MiB      0.0 MiB        valslist=[]
     9
    10    229.3 MiB    162.8 MiB        for i in xrange(0,1000000):
    11    229.3 MiB      0.0 MiB                keyslist.append((i,i,i))
    12    229.3 MiB      0.0 MiB                valslist.append(str(i)*3)
    13
    14    273.6 MiB     44.3 MiB        dflist=pd.DataFrame(valslist,  index=
pd.MultiIndex.from_tuples(keyslist, names=['a','b','c']))

对于相同的任务和内存类型,字典实现似乎并不具有内存效率。

修改

出于某种原因,当我将值更改为数字数组(更能代表我的数据)时,我的表现非常相似,有谁知道为什么会这样?

Filename: testdict.py

Line #    Mem usage    Increment   Line Contents
================================================
     4     66.9 MiB      0.0 MiB   @profile
     5                             def testdict():
     6
     7     66.9 MiB      0.0 MiB        d = {}
     8
     9    345.6 MiB    278.7 MiB        for i in xrange(0,1000000):
    10    345.6 MiB      0.0 MiB                d[(i,i,i)]=[0]*9
    11
    12    546.2 MiB    200.6 MiB        dfdict=pd.DataFrame(d.values(),  index=
pd.MultiIndex.from_tuples(d.keys(), names=['a','b','c']))

Filename: testlist.py

Line #    Mem usage    Increment   Line Contents
================================================
     4     66.3 MiB      0.0 MiB   @profile
     5                             def testlist():
     6
     7     66.3 MiB      0.0 MiB        keyslist=[]
     8     66.3 MiB      0.0 MiB        valslist=[]
     9
    10    314.7 MiB    248.4 MiB        for i in xrange(0,1000000):
    11    314.7 MiB      0.0 MiB                keyslist.append((i,i,i))
    12    314.7 MiB      0.0 MiB                valslist.append([0]*9)
    13
    14    515.2 MiB    200.6 MiB        dflist=pd.DataFrame(valslist,  index=
pd.MultiIndex.from_tuples(keyslist, names=['a','b','c']))