使用 Python 和 NumPy 的非常大的矩阵
Posted
技术标签:
【中文标题】使用 Python 和 NumPy 的非常大的矩阵【英文标题】:Very large matrices using Python and NumPy 【发布时间】:2010-11-06 10:30:41 【问题描述】:NumPy 是一个非常有用的库,通过使用它,我发现它能够轻松处理非常大 (10000 x 10000) 的矩阵,但开始遇到更大的矩阵(试图创建一个50000 x 50000 的矩阵失败)。显然,这是因为需要大量内存。
有没有一种方法可以在 NumPy 中以某种方式(比如 100 万乘以 100 万)本地创建巨大的矩阵(没有几 TB 的 RAM)?
【问题讨论】:
【参考方案1】:通常当我们处理大型矩阵时,我们将它们实现为Sparse Matrices。
我不知道 numpy 是否支持稀疏矩阵,但我找到了 this。
【讨论】:
【参考方案2】:据我对 numpy 的了解,不,但我可能是错的。
我可以向您推荐这个替代解决方案:将矩阵写入磁盘并以块的形式访问它。我建议你使用 HDF5 文件格式。如果您需要它透明,您可以重新实现 ndarray 接口以将磁盘存储的矩阵分页到内存中。如果您修改数据以将它们同步回磁盘上,请务必小心。
【讨论】:
如果我想访问 57600 x 57600 的整个矩阵怎么办?【参考方案3】:您应该能够使用 numpy.memmap 来内存映射磁盘上的文件。使用较新的 python 和 64 位机器,您应该拥有必要的地址空间,而无需将所有内容加载到内存中。操作系统应该只处理将部分文件保留在内存中。
【讨论】:
你能提供一个例子来说明如何使用它来做一些无法容纳在内存中的事情吗?【参考方案4】:要处理稀疏矩阵,您需要位于numpy
之上的scipy
包——有关scipy
为您提供的稀疏矩阵选项的更多详细信息,请参阅here。
【讨论】:
【参考方案5】:您是否在问如何在没有 TB 级 RAM 的情况下处理 2,500,000,000 个元素的矩阵?
在没有 80 亿字节 RAM 的情况下处理 20 亿个项目的方法是不将矩阵保存在内存中。
这意味着更复杂的算法可以从文件系统中分段获取它。
【讨论】:
不正确。如果 99.99%(对于实际示例)的元素为零,则矩阵的所有数据都可以保存在内存中。无需为每个零使用 4 个字节,因为您可以为确实存在的条目存储(row, column, value)
列表。
@EricWilson:问题中哪里表明矩阵是稀疏的?我完全错过了。你能提供报价吗?【参考方案6】:
numpy.array
s 应该存在于内存中。如果您想使用比 RAM 更大的矩阵,您必须解决这个问题。您至少可以采用两种方法:
-
尝试更有效的矩阵表示,利用矩阵所具有的任何特殊结构。例如,正如其他人已经指出的那样,稀疏矩阵(有很多零的矩阵)有有效的数据结构,比如
scipy.sparse.csc_matrix
。
修改您的算法以处理子矩阵。您只能从磁盘读取当前正在计算中使用的矩阵块。设计为在集群上运行的算法通常按块工作,因为数据分散在不同的计算机上,并且仅在需要时通过。例如,the Fox algorithm for matrix multiplication (PDF file)。
【讨论】:
3- 步入大数据范式并研究 MapReduce 等解决方案 对于第 2 点,你如何决定你的块有多大?有没有一种方法可以测量可用内存的数量并据此确定块的大小?【参考方案7】:Stefano Borini 的post 让我了解这种事情已经发展到什么程度了。
This is it. 它似乎基本上可以满足您的需求。 HDF5 将允许您存储非常大的数据集,然后以与 NumPy 相同的方式访问和使用它们。
【讨论】:
更好的选择可能是 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 对象。【参考方案8】:PyTables 和 NumPy 是必经之路。
PyTables 将以 HDF 格式将数据存储在磁盘上,并可选择压缩。我的数据集经常得到 10 倍的压缩,这在处理数千万或数亿行时非常方便。它也非常快;我 5 岁的笔记本电脑可以以 1,000,000 行/秒的速度处理类似 SQL 的 GROUP BY 聚合的数据。对于基于 Python 的解决方案来说还不错!
再次以 NumPy 重新数组的形式访问数据非常简单:
data = table[row_from:row_to]
HDF 库负责读取相关数据块并转换为 NumPy。
【讨论】:
所以您仍然需要自己将数据分成块进行处理?这只是一种简化与磁盘文件之间的转换的方法吗? 您是否有机会通过更清晰的一些示例来扩展您的答案? 目前,包h5py
还可以访问像 NumPy ndarray 这样的 HDF5 对象。 h5py
API 可能更类似于 NumPy。另请参阅 h5py
和 pytables
之间的差异(和连接)。 docs.h5py.org/en/stable/…【参考方案9】:
确保您使用的是 64 位操作系统和 64 位版本的 Python/NumPy。请注意,在 32 位架构上,您通常可以寻址 3GB 的内存(内存映射 I/O 等丢失了大约 1GB)。
使用 64 位和大于可用 RAM 的事物数组,您可以摆脱虚拟内存,但如果必须交换,事情会变慢。此外,内存映射(参见 numpy.memmap)是一种在磁盘上处理大文件而不将它们加载到内存中的方法,但同样,您需要有一个 64 位的地址空间才能使用它。 PyTables 也会为您完成大部分工作。
【讨论】:
【参考方案10】:这有点阿尔法,但http://blaze.pydata.org/ 似乎正在努力解决这个问题。
【讨论】:
【参考方案11】:有时一种简单的解决方案是为您的矩阵项使用自定义类型。根据您需要的数字范围,您可以使用手册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
【讨论】:
以上是关于使用 Python 和 NumPy 的非常大的矩阵的主要内容,如果未能解决你的问题,请参考以下文章
对于非常大的元组/文件/数据库记录/numpy.ndarray,linux“更多”类似于python中的代码?