NumPy的记忆效率

时间:2018-04-16 07:18:32

标签: python arrays list numpy

在学习NumPy时,我发现了它的优势,

NumPy比传统列表需要更少的内存。

import numpy as np
import sys

# Less Memory

l = range(1000)
print(sys.getsizeof(l[3])*len(l))

p = np.arange(1000)
print(p.itemsize*p.size)

这看起来令人信服,但比我尝试的时候,

print(sys.getsizeof(p[3])*len(p))

它显示的内存大小比列表大。

有人可以帮助我理解这种行为。

2 个答案:

答案 0 :(得分:1)

首先,正如评论getsizeof()中所提到的那样,为了这个目的而继续传播并不是一个很好的功能,因为it does not have to hold true for third-party extensions as it is implementation specific。此外,如documentation中所述,如果您想查找容器及其所有内容的大小,可以在https://code.activestate.com/recipes/577504/找到一个配方。

现在,关于Numpy数组,了解Numpy如何确定其数组的类型非常重要。为此,您可以阅读:How does numpy determin the array's dtype and what it means?

总而言之,Numpy在内存管理方面表现更好的最重要原因是它提供了各种类型的可用于不同类型数据的类型。你可以在这里阅读Numpy的数据类型:https://docs.scipy.org/doc/numpy-1.14.0/user/basics.types.html。另一个原因是Numpy是一个设计用于处理矩阵和数组的库,因此有很多关于它们的项目如何消耗内存的优化。

此外,值得注意的是,Python提供了一个array模块,旨在通过使用受约束的项类型来高效执行。

  

数组是序列类型,其行为与列表非常相似,只是存储在其中的对象类型受到约束。在对象创建时使用类型代码指定类型,类型代码是单个字符。

答案 1 :(得分:0)

理解数组的内存使用更容易:

In [100]: p = np.arange(10)
In [101]: sys.getsizeof(p)
Out[101]: 176
In [102]: p.itemsize*p.size
Out[102]: 80

p的数据缓冲区长度为80个字节。 p的其余部分是对象开销,属性如shapestrides等。

数组的索引元素是numpy对象。

In [103]: q = p[0]
In [104]: type(q)
Out[104]: numpy.int64
In [105]: q.itemsize*q.size
Out[105]: 8
In [106]: sys.getsizeof(q)
Out[106]: 32

所以这个乘法并没有告诉我们任何有用的东西:

In [109]: sys.getsizeof(p[3])*len(p)
Out[109]: 320

虽然这可能有助于我们估算此列表的大小:

In [110]: [i for i in p]
Out[110]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [111]: type(_[0])
Out[111]: numpy.int64
In [112]: sys.getsizeof(__)
Out[112]: 192

10个int64对象的列表占用320 + 192个字节,或多或少(列表开销及其指针缓冲区加上指向的大小对象)。

我们可以使用item从数组中提取int对象:

In [115]: p[0].item()
Out[115]: 0
In [116]: type(_)
Out[116]: int
In [117]: sys.getsizeof(p[0].item())
Out[117]: 24

相同len的列表可能会有不同的大小,具体取决于它们的增长空间:

In [118]: sys.getsizeof(p.tolist())
Out[118]: 144

事实上更复杂的是小整数与大整数不同的存储 - 低于256的存储是唯一的。