我有一个非常大的稀疏 Numpy 矩阵(类型为
numpy.ndarray
)。矩阵太大,可能必须存储在虚拟内存中。如何有效地将其转换为稀疏 Scipy 矩阵(来自 scipy.sparse
)(用于算术运算)?
以下是使用
dok_matrix
的直接转换,可能是由于内存问题而失败。将 dok_matrix
更改为 csr_matrix
会导致相同的内存问题。
In [1]: N=int(1e6)
In [2]: from scipy.sparse import dok_matrix
In [3]: import numpy as np
In [4]: mat=np.zeros((N,N))
In [5]: dok_matrix(mat)
zsh: killed ipython
我目前的方法是使用嵌套循环,即使我什么都不做也很慢。
In [9]: for i in range(N):
...: for j in range (N):
...: pass
有什么有效的解决方案可以将大型 (10^6 * 10^6) Numpy 稀疏矩阵转换为 Scipy 稀疏矩阵吗?
当您执行
mat = np.zeros((N,N))
时,Numpy 会分配一个充满零的大矩阵。为此,它向操作系统 (OS) 请求一个大的归零缓冲区。大多数操作系统实际上并不在物理内存中执行分配,而是在虚拟内存中执行分配。 内存页面在首次触摸期间进行映射。这意味着任何读取或写入都会导致虚拟页映射到物理内存中。请参阅这篇文章以获取有关此内容的更多信息。另请考虑阅读著名文章“每个程序员都应该了解内存”,以获取有关虚拟内存的更多信息。问题是 dok_matrix(mat)
需要读取整个矩阵才能创建稀疏矩阵,这样它将触发矩阵所有页面的映射,从而导致内存不足。当没有剩余空间时,Linux 的 OOM-Killer 会杀死使用过多内存的程序,因此会出现 killed ipython
消息。任何类型的稀疏矩阵都会出现同样的问题。主要问题是您无法读取整个创建的矩阵。事实上,创建这样的矩阵几乎毫无意义,除非您知道只会读取/写入一些微小的部分(而不是完整的矩阵)。解决方案是直接创建一个空间矩阵并像Numpy稠密矩阵一样填充它。它的速度要慢得多,但这是使用稀疏矩阵所付出的代价。 DOK 矩阵通常会占用大量内存,除非只填充很少的项。话虽这么说,DOK 矩阵是随机访问速度最快的矩阵之一(因为它们是在内部使用哈希表实现的)。 CSR 对于创建后就不会更改的矩阵很有用(即修改 CSR 矩阵非常慢)并且每行只有很少的非零项。请注意,可以从数据一维数组和 (row_ind, col_ind)
数组元组快速创建 CSR 矩阵。请参阅
文档了解更多信息。 矩阵的稀疏性,即比率
NumberOfNonZeroValue / NumberOfValues
需要(非常)小才能使稀疏矩阵有用。稀疏矩阵往往很慢,因为它们的内部表示在一种压缩矩阵上运行。