具有稀疏数据的列表比与 numpy 数组相同的数据消耗更少的内存

List with sparse data consumes less memory then the same data as numpy array

我正在使用非常高维的向量进行机器学习,并且正在考虑使用 numpy 来减少使用的内存量。我 运行 一个快速测试,看看我可以使用 numpy (1)(3):

节省多少内存

标准列表

import random
random.seed(0)
vector = [random.random() for i in xrange(2**27)]

Numpy 数组

import numpy
import random
random.seed(0)
vector = numpy.fromiter((random.random() for i in xrange(2**27)), dtype=float)

内存使用情况(2)

Numpy array: 1054 MB
Standard list: 2594 MB

和我预想的一样

通过使用原生浮点数分配连续的内存块,numpy 仅消耗标准列表使用的内存的一半左右。

因为我知道我的数据很空闲,所以我用稀疏数据做了同样的测试。

标准列表

import random
random.seed(0)
vector = [random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)]

Numpy 数组

from numpy import fromiter
from random import random
random.seed(0)
vector = numpy.fromiter((random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)), dtype=float)

内存使用情况(2)

Numpy array: 1054 MB
Standard list: 529 MB

突然之间,python 列表使用的内存量是 numpy 数组使用的一半!为什么?

我能想到的一件事是 python 在检测到它包含非常稀疏的数据时动态切换到 dict 表示。检查这个可能会增加很多额外的 运行 时间开销,所以我真的不认为这是怎么回事。

备注

  1. 我为每个测试开始了一个全新的 python shell。
  2. 使用 htop 测量的内存。
  3. 运行 在 32 位 Debian 上。

Python 列表只是对 Python 对象的引用(指针)数组。在 CPython(通常的 Python 实现)中,列表稍微过度分配以使扩展更有效,但它 never 被转换为字典。有关详细信息,请参阅源代码:List object implementation

在列表的稀疏版本中,您有很多指向单个 int 0 对象的指针。这些指针占用 32 位 = 4 个字节,但你的 numpy 浮点数肯定更大,可能是 64 位。

FWIW,为了使稀疏列表/数组测试更准确,您应该在两个版本中使用相同的种子调用 random.seed(some_const),以便在两个 Python 列表中获得相同数量的零和 numpy 数组。