在python中处理大型密集矩阵

ih99xse1  于 2022-12-10  发布在  Python
关注(0)|答案(6)|浏览(252)

基本上,在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只是作为一个例子,说明什么是 * 不 * 工作的。
有什么建议吗?

Edit我最后重写了所有的逻辑,这样它就不再存储任何冗余值,从而将内存使用从O*n^2减少到O*((n*(n-1))/2)

基本上,这整个事件是handshake problem的一个版本,所以我已经从存储所有链接切换到只存储每个链接的一个版本。
这不是一个完整的解决方案,但我通常没有任何数据集大到足以溢出它,所以我认为它会工作。PyTables是真的很有趣,但我不知道任何SQL,似乎没有任何好的传统切片或基于索引的方式来访问表数据。我可能会在未来重新考虑这个问题。

1zmg4dgp

1zmg4dgp1#

我找到了解决办法
h5py
它是一个库,基本上提供了一个类似numpy的接口,但使用压缩的memmapped文件来存储任意大小的数组(它基本上是HDF5的 Package 器)。
PyTables是在它的基础上构建的,是PyTables引导我找到了它。但是,我不需要PyTables主要提供的任何SQL功能,而且PyTables没有提供我真正想要的干净的类似数组的接口。
h5py基本上就像一个numpy数组,只是以不同的格式存储数据。
它似乎也没有数组大小的限制,除了磁盘空间。我目前正在uint16的100,000 * 100,000数组上进行测试。

eanckbw9

eanckbw92#

PyTables可以通过使用memmap和一些巧妙的压缩来处理任意大小的表(数百万列!)。
表面上看,它为python提供了类似SQL的性能,但是它需要大量的代码修改。
我不会接受这个答案,除非我做了一个更彻底的审查,以确保它实际上可以做我想要的,或者有人提供一个更好的解决方案。

kmynzznz

kmynzznz3#

对于20,000 x 20,000,您正在寻找12GB的RAM?
难道你不会最终在交换地狱试图与一个12GB的win32,人为地限制内存的操作系统可以解决工作?
我会寻找一个操作系统,可以支持12GB(32 bin赢2003服务器可以,如果你需要坚持与32位的窗口),但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)
j0pj023g

j0pj023g4#

如果你有N个对象,保存在一个列表L中,你希望存储每个对象之间的相似度,即O(N**2)相似度.在similarity(A, B) == similarity(B, A)similarity(A, A) == 0的共同条件下,你所需要的只是一个三角形的相似性数组S,这个数组中的元素数是N*(N-1)//2,你应该可以使用数组。数组。将您的相似性保持为一个浮点数只需要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)。
如果以上内容不适合您,那么您可以解释“"“每个项[在哪个容器中?]都是一个自定义类,并存储指向另一个类的指针和表示它与该类“接近程度”的数字。””和“"“我不想存储数字,我想存储对类的引用”""。即使在替换“class我很难理解你的意思。

s5a0g9ez

s5a0g9ez5#

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

px9o7tmv

px9o7tmv6#

您可以使用uint8来减少内存使用量,但请小心避免溢位错误。uint16需要两个字节,因此在您的范例中,最低内存需求为80008000302字节= 3.84 Gb。
如果第二个示例失败,则需要一台新计算机。内存要求为20000
200002 字节=800 Mb。
我的建议是,你可以尝试创建更小的矩阵,并使用“top”、“ps v”或gnome系统监视器来检查python进程使用的内存。从检查一个小矩阵的单个线程开始,然后进行计算。注意,你可以通过写del(x)来释放变量x的内存。这对测试很有用。
你的机器上有多少内存?pytables使用多少内存来创建一个2000020000的表?numpy使用uint8使用多少内存来创建一个2000020000的表?

相关问题