【问题标题】:Large matrix multiplication in Python - what is the best option?Python中的大矩阵乘法 - 最好的选择是什么?
【发布时间】:2013-12-21 11:11:32
【问题描述】:

我有两个 c 的布尔稀疏方阵。从 12BM 的数据生成 80,000 x 80,000(当我使用 GB 的数据时,矩阵可能会大几个数量级)。

我想将它们相乘(这会产生一个三角矩阵 - 但是我没有得到这个,因为我没有将点积限制为产生一个三角矩阵)。

我想知道将它们相乘的最佳方法是什么(内存方面和速度方面) - 我将在具有 >60GB RAM 的 m2.4xlarge AWS 实例上进行计算。出于速度原因,我更愿意将计算保留在 RAM 中。

我很欣赏 SciPy 和 h5py 的稀疏矩阵,但两者都没有经验。

最好的选择是什么?

提前致谢

更新:布尔矩阵的稀疏性

【问题讨论】:

  • 你是否将它们作为布尔值相乘,即结果是布尔类型?以及您的数据有多稀疏,占多少?
  • 是的,我将它们作为布尔值与 0、1 相乘,因此得到的结果矩阵中的数字为 0 或大于 0 的整数。如何检查矩阵的稀疏性?
  • 你生成的,你可以从算法中知道。您可以使用sum() 检查数量并除以总大小(在您的情况下为 6.4*10**9)
  • 布尔矩阵中其余 0.6% 的数字为零
  • 我不确定,但我认为结果通常不会稀疏,您将无法将其存储在几十 GB 的 RAM 中。无论如何,检查 scipy.sparse 中的 csr 和 csc 稀疏格式。

标签: python numpy sparse-matrix pytables h5py


【解决方案1】:

-- 已编辑以满足以下评论/否决者--

您在问如何快速轻松地乘以矩阵。

解决方案 1:这是一个已解决的问题:使用 numpy.所有这些操作在 numpy 中都很容易,并且由于它们是用 C 实现的,因此速度非常快。

另见:

SciPy 和 Numpy 具有 稀疏矩阵 和矩阵乘法。它不使用太多内存,因为(至少如果我用 C 编写它)它可能使用链表,因此只会使用数据点总和所需的内存,加上一些开销。而且,与纯 python 解决方案相比,它几乎肯定会非常快。

解决方案 2

这里的另一个答案建议将值存储为 (x, y) 的元组,假设值是 False 除非它存在,那么它就是 true。与之替代的是带有 (x, y, value) 元组的数值矩阵。

REGARDLESS:将这些相乘将是讨厌时间:找到第一个元素,决定要乘以哪个其他数组元素,然后在整个数据集中搜索该特定元组,如果存在,则相乘并将结果插入结果矩阵。

解决方案 3(首选与解决方案 2,恕我直言)

我更喜欢这个,因为它更简单/更快。

用一组字典表示你的稀疏矩阵。矩阵一是一个字典,其元素位于 (x, y) 且值 v 为 (x1,y1, x2,y2 等):

matrixDictOne = { 'x1:y1' : v1, 'x2:y2': v2, ... }
matrixDictTwo = { 'x1:y1' : v1, 'x2:y2': v2, ... }

由于 Python dict 查找是 O(1)(好吧,不是真的,可能更接近 log(n)),它很快。这不需要在乘法之前搜索整个第二个矩阵的数据以查找元素的存在。所以,它很快。乘法容易写,表示也容易理解。

解决方案 4(如果你喜欢惩罚)

使用所需大小的内存映射文件编写此解决方案。使用所需大小的空值初始化文件。自己计算偏移量并在进行乘法运算时写入文件中的适当位置。 Linux 有一个 VMM,它会为您分页进出,而您只需很少的开销或工作。这是一个非常非常大的矩阵的解决方案,这些矩阵不稀疏,因此不适合内存。

请注意,这解决了以下投诉者的投诉,它不适合记忆。但是,OP 确实说 sparse,这意味着很少有实际数据点分布在巨型阵列中,而 Numpy / SciPy 可以本地处理这个问题,因此很好(费米实验室的很多人经常使用 Numpy / SciPy,我'相信稀疏矩阵代码已经过良好测试)。

【讨论】:

  • 你读过这个问题吗?来自 OP 问题的矩阵可能太大而无法存储在 RAM 中。而且任何已知的矩阵乘法算法都不比O(n^2.7)好,这对于OP情况来说是一个巨大的数字。
  • 不同意:稀疏矩阵不分配 m*n 的数组。它只分配元素的实际数量使用的内存。 OP 引用了一个非常大的 sparse 矩阵。在 Python 中编写稀疏矩阵可能很麻烦。由于 SciPy / Numpy 使用 C 语言优化的数组,可能是优化内存的链表,这是很有可能的。任何大部分为空的稀疏矩阵乘以另一个大部分为空的稀疏矩阵都应该绝对适合内存。另外,在linux系统上,VMM可以将内存映射到磁盘上,效果很好。
  • 值得注意的是,scipy 实际上并没有“在C 中实现”,主要由C++FORTRAN 组成。
  • Kevin,注意稀疏度指定为 0.6% 的数据,实际上并不是很稀疏。这就是为什么我认为当数量级按规定增长并且手头有 8*106x8*106 矩阵时,它将包含 0.006*6.4*1013=3.84 *1011 个非零值,这是一个巨大的数字,不适合内存。以前的尺寸8*10**5是这方面的边界,要小心。抛开乘法复杂性的幂律
【解决方案2】:

如果您的矩阵相对为空,则可能值得将它们编码为非 False 值的数据结构。说一个描述非 False 值位置的元组列表。或者以元组为键的字典。

如果您使用例如元组列表,您可以使用列表推导来查找第二个列表中可以与第一个列表中的元素相乘的项目。

a = [(0,0), (3,7), (5,2)] # et cetera
b = ... # idem

for r, c in a:
    res = [(r, k) for j, k in b if k == j]

【讨论】:

  • 见上面的附加答案,如果数据集很大,这将非常耗时。我猜如果它是几百个或更少的数据点,我认为这可能相当快。
猜你喜欢
  • 1970-01-01
  • 2016-02-06
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 2011-11-20
  • 2013-09-22
  • 2018-03-09
相关资源
最近更新 更多