基本上,在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,并且似乎没有任何好的传统切片或基于索引的方式来访问表数据。我将来可能会重新审视这个问题。
答案 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)
您可以在NumPy (see SciPy)文档(数组/矩阵)中找到一些建议:
答案 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表时会占用多少内存?