4

基本上,在 python 中存储和使用密集矩阵的最佳方法是什么?

我有一个项目可以在数组中的每个项目之间生成相似度指标。

每个项目都是一个自定义类,并存储一个指向另一个类的指针和一个表示它与该类“接近”的数字。

现在,它可以出色地处理大约 8000 个项目,之后它会因内存不足错误而失败。
基本上,如果您假设每次比较使用约 30(根据测试似乎准确)字节来存储相似性,这意味着所需的总内存为:
numItems^2 * itemSize = Memory
因此,内存使用量是基于项目数的指数。
在我的情况下,每个链接的内存大小约为 30 字节,因此:
8000 * 8000 * 30 = 1,920,000,000 bytes, or 1.9 GB
这正好是单个线程的内存限制。

在我看来,必须有一种更有效的方法来做到这一点。我看过memmapping,但它已经在计算密集型只是为了生成相似度值,并且通过硬盘驱动器瓶颈似乎有点荒谬。

编辑
我看过 numpy 和 scipy。不幸的是,它们也不支持非常大的数组。

>>> np.zeros((20000,20000), dtype=np.uint16)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError
>>>

进一步编辑
Numpy 似乎很受欢迎。但是,numpy 不会真正做我想做的事,至少没有另一个抽象层。

不想存储数字,我想存储对类的引用。Numpy 支持对象,但这并不能真正解决数组大小问题。我提出了 numpy 只是作为不起作用的一个例子

有什么建议吗?

编辑好吧,我最后只是重写了所有逻辑,因此它不再存储任何冗余值,从而将内存使用量从 减少O*n^2O*((n*(n-1))/2).

基本上,这整个事件是握手问题的一个版本,所以我已经从存储所有链接切换到每个链接只存储一个版本。

这不是一个完整的解决方案,但我通常没有足够大的数据集来溢出它,所以我认为它会解决的。PyTables 真的很有趣,但我不知道任何 SQL,而且似乎没有任何好的传统切片或基于索引的方式来访问表数据。我将来可能会重新讨论这个问题。

4

6 回答 6

11

好吧,我找到了我的解决方案:
h5py

它是一个库,基本上提供了一个类似 numpy 的界面,但使用压缩的 memmapped 文件来存储任意大小的数组(它基本上是 HDF5 的包装器)。

PyTables 是建立在它之上的,而 PyTables 实际上把我引向了它。但是,我不需要任何作为 PyTables 主要产品的 SQL 功能,而且 PyTables 没有提供我真正想要的干净的类似数组的接口。

h5py 基本上就像一个 numpy 数组,只是以不同的格式存储数据。

除了磁盘空间之外,它似乎对数组大小也没有限制。我目前正在对 100,000 * 100,000 的 uint16 数组进行测试。

于 2010-07-23T02:47:56.653 回答
3

PyTables可以通过使用 memmap 和一些巧妙的压缩来处理任意大小的表(数百万列!)。

从表面上看,它为 python 提供了类似 SQL 的性能。但是,它将需要大量的代码修改。

在我进行更彻底的审查之前,我不会接受这个答案,以确保它能够真正做到我想要的。或者有人提供了更好的解决方案。

于 2010-07-11T01:57:44.210 回答
1

对于 20,000 x 20,000,您正在寻找 12GB 的 RAM?

您是否不会最终陷入交换地狱,试图在 win32 中使用 12GB 来人为地限制操作系统可以寻址的内存?

我正在寻找可以支持 12GB 的操作系统(如果您需要坚持使用 32 位 Windows,32 bin win 2003 服务器可以),但是具有 64 位操作系统和 16GB 内存的 64 位机器似乎更合适。

升级的好借口:)

64 位 numpy 可以支持你的矩阵

Python 2.5.2 (r252:60911, Jan 20 2010, 23:14:04) 
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.zeros((20000,20000),dtype=np.uint16)
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ..., 
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]], dtype=uint16)
于 2010-07-10T10:52:21.863 回答
0

您可能会在NumPy(参见 SciPy)文档(数组/矩阵)中找到一些建议:

于 2010-07-10T09:52:20.137 回答
0

如果您有 N 个对象,保存在列表 L 中,并且您希望存储每个对象和其他对象之间的相似性,这就是O(N**2)相似性。在 和 的共同条件下similarity(A, B) == similarity(B, A)similarity(A, A) == 0您所需要的只是一个相似的三角阵列 S。该数组中的元素数将为N*(N-1)//2. 您应该能够为此目的使用 array.array。将您的相似性保持为浮点数只需要 8 个字节。如果您可以将相似度表示为 in 中的整数range(256),则使用无符号字节作为 array.array 元素。

所以这大约是 8000 * 8000 / 2 * 8 即大约 256 MB。仅使用一个字节来表示相似性意味着只有 32 MB。S[i*N-i*(i+1)//2+j]您可以通过模拟方形数组而不是使用 S[i*N+j]` 来避免三角形事物的缓慢索引计算;内存将翻倍至(浮点数为 512 MB,字节数为 64 MB)。

如果上述内容不适合您,那么也许您可以解释“”“每个项目[在哪个容器中?] 是一个自定义类,并存储一个指向另一个类的指针和一个表示它与该类“接近”的数字。 “”和“”“我不想存储数字,我想存储对类的引用”“”。即使在用“对象”替换“类”之后,我也很难理解什么你的意思是。

于 2010-07-11T05:10:53.373 回答
-1

使用 uint8 可以减少内存使用,但要小心避免溢出错误。uint16 需要两个字节,因此您的示例中的最小内存要求是 8000*8000*30*2 字节 = 3.84 Gb。

如果第二个示例失败,那么您需要一台新机器。内存要求为 20000*20000*2*bytes =800 Mb。

我的建议是您尝试创建更小的矩阵并使用“top”、“ps v”或 gnome 系统监视器来检查您的 python 进程使用的内存。开始检查带有小矩阵的单个线程并进行数学计算。请注意,您可以通过编写 del(x) 来释放变量 x 的内存。这对测试很有用。

你机器上的内存是多少?pytables创建一个20000*20000的表需要多少内存?numpy使用uint8创建一个20000*20000的表需要多少内存?

于 2010-07-10T11:44:05.057 回答