Answers:
NumPy的数组比Python列表更紧凑-您在Python中描述的列表列表至少需要20 MB左右,而单元格中具有单精度浮点数的NumPy 3D数组则需要4 MB。使用NumPy可以更快地读取和写入项目。
也许您只关心一百万个单元就不会那么在意,但是您肯定会关心十亿个单元-两种方法都不适合32位体系结构,但是使用64位版本,NumPy可以节省约4 GB ,仅Python一项就至少需要12 GB(很多指针的大小加倍),这是一个昂贵得多的硬件!
差异主要是由于“间接性”造成的-Python列表是指向Python对象的指针的数组,每个指针至少4个字节,对于最小的Python对象也至少包含16个字节(类型指针为4,引用计数为4,类型为4值-内存分配器舍入为16)。NumPy数组是统一值的数组-单精度数字每个占用4个字节,双精度数字每个占用8个字节。灵活性较差,但您要为标准Python列表的灵活性付出高昂的代价!
getsizeof
不可靠。该文档明确指出:仅考虑直接归因于对象的内存消耗,而不考虑它所引用的对象的内存消耗。 这意味着,如果您嵌套了python列表,则不会考虑元素的大小。
getsizeof
列表上的内容仅告诉您列表对象本身消耗了多少RAM以及其数据数组中的指针消耗的RAM,而没有告诉您这些指针引用的对象消耗了多少RAM。
float
的4 GB numpy数组(4个字节)将转换为接近32 GB的list
s和Python float
s(实际上是C double
),而不是12 GB。每个float
在64位Python上占用约24个字节(假设分配器中没有对齐损失),另加8个字节list
来保存引用(并且忽略list
s本身的过度分配和对象标头,这可能会增加另一个GB,具体取决于究竟发生了多少超额分配)。
NumPy不仅效率更高;这也更加方便。您可以免费获得许多矢量和矩阵运算,有时这可以避免不必要的工作。而且它们也得到有效实施。
例如,您可以将多维数据集直接从文件读取到数组中:
x = numpy.fromfile(file=open("data"), dtype=float).reshape((100, 100, 100))
沿第二维求和:
s = x.sum(axis=1)
查找哪些单元格高于阈值:
(x > 0.5).nonzero()
删除沿第三维的每个偶数索引切片:
x[:, :, ::2]
同样,许多有用的库都可以与NumPy数组一起使用。例如,统计分析和可视化库。
即使您没有性能问题,学习NumPy也是值得的。
Alex提到了内存效率,Roberto提到了便利性,这些都是不错的地方。对于其他一些想法,我将提到速度和功能。
功能性:NumPy,FFT,卷积,快速搜索,基本统计信息,线性代数,直方图等都内置了很多功能。实际上,没有FFT谁能活下去?
速度:这是一项对列表和NumPy数组求和的测试,表明NumPy数组的求和速度快10倍(在此测试中,里程可能会有所不同)。
from numpy import arange
from timeit import Timer
Nelements = 10000
Ntimeits = 10000
x = arange(Nelements)
y = range(Nelements)
t_numpy = Timer("x.sum()", "from __main__ import x")
t_list = Timer("sum(y)", "from __main__ import y")
print("numpy: %.3e" % (t_numpy.timeit(Ntimeits)/Ntimeits,))
print("list: %.3e" % (t_list.timeit(Ntimeits)/Ntimeits,))
在我的系统上(运行备份时),它会给出:
numpy: 3.004e-05
list: 5.363e-04
这是scipy.org网站上的常见问题解答中的一个很好的答案:
与(嵌套)Python列表相比,NumPy数组有什么优势?
Python的列表是有效的通用容器。它们支持(相当)高效的插入,删除,附加和连接,并且Python的列表理解使它们易于构造和操作。但是,它们有一定的局限性:它们不支持“向量化”操作,例如逐元素加法和乘法,并且它们可以包含不同类型的对象这一事实意味着Python必须为每个元素存储类型信息,并且必须执行类型分派代码在每个元素上操作时。这也意味着有效的C循环几乎无法执行列表操作-每次迭代都需要类型检查和其他Python API簿记。