使用Python和NumPy的超大型矩阵


86

NumPy是一个非常有用的库,通过使用它,我发现它能够轻松处理非常大的矩阵(10000 x 10000),但是开始处理任何更大的矩阵(试图创建50000 x 50000的矩阵)失败)。显然,这是因为需要大量内存。

是否有一种方法可以以某种方式(没有几个terrabytes的RAM)在NumPy中本地创建大型矩阵(比如说一百万乘一百万)?

Answers:


91

PyTables和NumPy是必经之路。

PyTables将以HDF格式(可选压缩)将数据存储在磁盘上。我的数据集经常得到10倍压缩,这在处理数千万或几亿行时非常方便。它也非常快。我5岁的笔记本电脑可以以每秒1,000,000行/秒的速度执行类似SQL的GROUP BY聚合的数据。对于基于Python的解决方案来说还不错!

再次作为NumPy数组访问数据非常简单:

data = table[row_from:row_to]

HDF库负责读取相关的数据块并将其转换为NumPy。


4
因此,您仍然必须自己将数据分解成块进行处理?这只是简化与磁盘文件之间的转换的一种方法?
Endlith

您是否有机会通过更清晰的示例来扩展答案?
亚当B

56

numpy.arrays旨在保留在内存中。如果要使用大于RAM的矩阵,则必须解决该问题。您可以遵循至少两种方法:

  1. 尝试使用矩阵具有的任何特殊结构的更有效的矩阵表示形式。例如,正如其他人已经指出的那样,对于稀疏矩阵(具有很多零的矩阵)有高效的数据结构,例如scipy.sparse.csc_matrix
  2. 修改您的算法以处理子矩阵。您只能从磁盘读取当前在计算中使用的矩阵块。设计用于集群上的算法通常按块运行,因为数据分散在不同的计算机上,并且仅在需要时才通过。例如,用于矩阵乘法的Fox算法(PDF文件)

4
3-介入大数据范式并研究MapReduce
Medeiros

对于数字2,您如何决定将自己的块做成多大?有没有一种方法可以测量可用内存的数量并根据此大小来确定块的大小?
endlith 2015年

30

您应该能够使用numpy.memmap来在磁盘上对文件进行内存映射。使用较新的python和64位计算机,您应该具有必要的地址空间,而无需将所有内容都加载到内存中。操作系统只应处理部分文件在内存中。


19
您能否提供一个示例,说明如何使用它来执行内存中无法容纳的操作?
endolith

24

要处理稀疏矩阵,您需要scipy位于其顶部的软件包numpy-有关可提供给您的稀疏矩阵选项的详细信息,请参见此处scipy


11

Stefano Borini的帖子让我研究了这种事情已经走了多远。

就是这个。 它看起来基本上可以满足您的要求。HDF5允许您存储非常大的数据集,然后以与NumPy相同的方式访问和使用它们。


9
更好的选择可能是PyTables。它比HDF5核心功能更高(H5Py仅比可从Python访问的低级API多一点)。上周的2.2测试版也提供了解决此问题的工具:pytables.org/moin/ReleaseNotes/Release_2.2b1添加了Expr,该类[可以]计算可以对任意大数进行操作的表达式(例如'3 * a + 4 * b')数组,同时优化资源[...]。它与Numexpr包相似,但是除了NumPy对象之外,它还接受基于磁盘的同质数组,例如Array,CArray,EArray和Column PyTables对象。
AFoglia 2009年

5

确保您使用的是64位操作系统和64位版本的Python / NumPy。请注意,在32位体系结构上,您通常可以寻址3GB内存(其中约1GB丢失到了内存映射的I / O等)。

使用64位的东西阵列比可用的RAM大,您可以摆脱虚拟内存,尽管如果必须交换,东西会变慢。同样,内存映射(请参阅numpy.memmap)是一种处理磁盘上的大文件而不将其加载到内存中的方法,但是同样,您需要具有64位地址空间才能使用它,这样才能发挥很多作用。PyTables也将为您完成大部分操作。



4

有时,一种简单的解决方案是为矩阵项使用自定义类型。根据所需数字的范围,您可以使用手册dtype,特别是较小的物品。由于Numpy默认情况下会考虑对象的最大类型,因此在许多情况下这可能是一个有用的想法。这是一个例子:

In [70]: a = np.arange(5)

In [71]: a[0].dtype
Out[71]: dtype('int64')

In [72]: a.nbytes
Out[72]: 40

In [73]: a = np.arange(0, 2, 0.5)

In [74]: a[0].dtype
Out[74]: dtype('float64')

In [75]: a.nbytes
Out[75]: 32

并使用自定义类型:

In [80]: a = np.arange(5, dtype=np.int8)

In [81]: a.nbytes
Out[81]: 5

In [76]: a = np.arange(0, 2, 0.5, dtype=np.float16)

In [78]: a.nbytes
Out[78]: 8

3

您是否在问如何在没有TB的RAM的情况下处理2,500,000,000元素矩阵?

在没有80亿字节RAM的情况下处理20亿个项目的方法是不将矩阵保留在内存中。

这意味着需要更复杂的算法来分段地从文件系统中获取它。


7
不对。如果99.99%(对于实际示例)的元素为零,则矩阵的所有数据都可以保留在内存中。当您可以存储(row, column, value)确实存在的那些条目的列表时,就不需要为每个零使用4个字节。
埃里克·威尔逊

6
@EricWilson:问题在哪里表明矩阵稀疏?我完全错过了。你能提供报价吗?
S.Lott


1

据我了解的numpy,不,但是我可能是错的。

我可以为您提出这个替代解决方案:将矩阵写在磁盘上并成块访问。我建议您使用HDF5文件格式。如果透明地需要它,则可以重新实现ndarray接口以将磁盘存储的矩阵分页到内存中。如果您修改数据以使其同步回磁盘,请小心。


如果我想通过57600访问整个57600矩阵,该怎么办?
Gunjan naik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.