在python中处理大型密集矩阵

时间:2010-07-10 09:29:29

标签: python matrix 32-bit python-2.6 windows-xp

基本上,在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^2减少到O*((n*(n-1))/2)

基本上,整个事件都是handshake problem的一个版本,所以我已经从存储所有链接切换到每个链接的单个版本。

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

6 个答案:

答案 0 :(得分:11)

嗯,我找到了解决方案:
h5py

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

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

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

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

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:1)

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

难道你最终不会试图在win32中使用12GB,这会人为地限制操作系统可以解决的内存吗?

我一直在寻找能够支持12GB的操作系统(如果你需要坚持使用32位窗口,可以使用32位bin 2003服务器),但是64位64位操作系统和16GB内存的机器似乎更合适

升级的好借口:)

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)

答案 3 :(得分:0)

答案 4 :(得分:0)

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

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

如果以上内容不适合你,那么也许你可以解释“”“每个项目[在哪个容器中?]是一个自定义类,并存储一个指向另一个类的指针和一个代表它的”亲密度“的数字。那个类。“”和“”“我不想存储数字,我想存储对类”“”的引用。即使用“object(s)”替换“class(es)”,我也在努力了解你的意思。

答案 5 :(得分:-1)

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

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

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

您机器上的内存是多少? pytables用于创建20000 * 20000表的内存量是多少? numpy使用uint8创建20000 * 20000表时会占用多少内存?