30

我正在尝试创建一个包含 2 708 000 000 个元素的矩阵。当我尝试创建一个这种大小的 numpy 数组时,它给了我一个值错误。有什么办法可以增加最大数组大小吗?

a=np.arange(2708000000)

ValueError Traceback(最近一次调用最后一次)

ValueError:超出最大允许大小

4

4 回答 4

19

您正在尝试创建一个包含 27 亿个条目的数组。如果您正在运行 64 位 numpy,每个条目 8 个字节,那么总共将是 20 GB。

所以几乎可以肯定你只是用完了你机器上的内存。numpy 中没有一般的最大数组大小。

于 2013-01-25T16:06:17.027 回答
14

ValueError 表示大小太大而无法分配,而不是内存不足。在我的笔记本电脑上,使用 64 位 python,如果我减少位数,我可以分配它:

In [16]: a=np.arange(2708000000)
---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-16-aaa1699e97c5> in <module>()
----> 1 a=np.arange(2708000000)

MemoryError: 

# Note I don't get a ValueError

In [17]: a = np.arange(2708000000, dtype=np.int8)

In [18]: a.nbytes
Out[18]: 2708000000

In [19]: a.nbytes * 1e-6
Out[19]: 2708.0

在您的情况下, arange 使用int64位,这意味着它是 16 倍,或大约 43 GB。一个 32 位进程只能访问大约 4 GB 的内存。

根本原因是用于访问数据的指针的大小以及您可以用这些位表示多少个数字:

In [26]: np.iinfo(np.int32)
Out[26]: iinfo(min=-2147483648, max=2147483647, dtype=int32)
In [27]: np.iinfo(np.int64)
Out[27]: iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)

请注意,如果我尝试创建一个大得离谱的数组,我可以复制您的 ValueError :

In [29]: a = np.arange(1e350)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-29-230a6916f777> in <module>()
----> 1 a = np.arange(1e350)

ValueError: Maximum allowed size exceeded

如果您的机器有很多内存,如您所说,它将是 64 位,因此您应该安装 Python 64 位才能访问它。另一方面,对于如此大的数据集,您应该考虑使用核外计算的可能性。

于 2014-05-24T00:07:49.673 回答
8

我能够创建一个大小为 60 亿的数组,占用了 45GB 的内存。默认情况下,numpy 创建了一个 dtype 为 float64 的数组。通过降低精度,我能够节省大量内存。

np.arange(6000000000,dtype=np.dtype('f8'))
np.arange(6000000000,dtype=np.dtype('f4'))
#etc...

默认 == float64

  • np.float64——45.7GB

  • np.float32 -- 22.9GB

  • np.int8——5.7GB

显然8位整数不能存储6B的值。 我确信在某个时候存在最大大小,但我怀疑它在 2016 年已经超出了任何可能。有趣的是,“Python Blaze”允许您在磁盘上创建 numpy 数组。我记得前段时间玩过它并创建了一个占用 1TB 磁盘的超大阵列。

于 2016-07-18T00:41:37.873 回答
-9

确实和系统最大地址长度有关,简单来说是32位系统还是64位系统。这是对这些问题的解释,最初来自 Mark Dickinson

简短的回答:Python 对象开销正在杀死你。在 64 位机器上的 Python 2.x 中,字符串列表每个列表条目消耗 48 个字节,甚至在考虑字符串内容之前。对于您描述的数组大小,这超过了 8.7 Gb 的开销。在 32 位机器上会好一些:每个列表条目只有 28 个字节。

更详细的解释:您应该知道 Python 对象本身可能非常大:即使是简单的对象,如整数、浮点数和字符串。在您的代码中,您最终会得到一个字符串列表列表。在我的(64 位)机器上,即使是一个空字符串对象也会占用 40 个字节,为此您需要为指向内存中该字符串对象的列表指针添加 8 个字节。所以这已经是每个条目 48 个字节,或大约 8.7 Gb。鉴于 Python 一次以 8 个字节的倍数分配内存,并且您的字符串几乎可以肯定是非空的,您实际上正在查看每个条目 56 或 64 个字节(我不知道您的字符串有多长)。

可能的解决方案:

(1) 通过将条目从字符串转换为适当的整数或浮点数,您可能会做得更好。

(2) 通过使用 Python 的数组类型(与列表不同!)或使用 numpy:你会做得更好:那么你的 int 或 float 将只占用 4 或 8 个字节。

从 Python 2.6 开始,您可以使用 sys.getsizeof 函数获取有关对象大小的基本信息。请注意,如果将其应用于列表(或其他容器),则返回的大小不包括包含的列表对象的大小;仅用于容纳这些对象的结构。这是我机器上的一些值。

于 2014-05-23T22:06:51.987 回答