我正在处理大型矩阵,例如Movielens 20m dataset。我对在线文件进行了重组,使其与页面上提到的尺寸(138000 x 27000)匹配,因为原始文件包含的索引更大(138000 x 131000),但是包含许多空列。 只需扔掉那些空列并重新索引就可以得到所需的尺寸。
无论如何,将稀疏的csv文件转换为密集格式的代码段看起来像这样:
import pandas as pd
from scipy import sparse
# note that the file is not the one described in the link, but the smaller one
X = pd.read_csv("ml-20m-dense.dat", sep=",", header=None)
mat = sparse.coo_matrix((X[2], (X[0], X[1]))).todense()
现在,内存中的估计大小应该接近 138000 * 27000 * 8 /(1024 ^ 3)= 27.5 GB 。
但是,当我用htop检查进程时,虽然保留了大约32 GB的 virtual 内存,但内存消耗仅显示7 GB左右。
起初,我认为这可能是由于熊猫阅读器或scipy.sparse
程序包的一些“效率提高”所致,从而避免了内存消耗的激增。
但是即使在我对其调用PCA函数之后,它也永远不会将活动内存消耗增加到应有的数量。
请注意,调用mat.nbytes
会返回估计的确切数量,因此NumPy似乎至少知道该数据。
(供参考的PCA代码:)
from fbpca import pca
result = pca(mat, k=3, raw=False, n_iter=3)
请注意,尽管fbpca使用了随机算法,并且我仅在计算前三个分量,但是code仍对输入矩阵与(方法)进行(单个但完整的)矩阵乘法较小)的随机矩阵。本质上,它仍然必须至少访问一次输入矩阵中的每个元素。
最后一句话也与我发现的帖子this略有不同,因为在该帖子中,元素从未真正访问过。
答案 0 :(得分:2)
我认为您的问题出在todense()
调用中,该调用使用了np.asmatrix(self.toarray(order=order, out=out))
internally。
toarray
使用np.zeros
创建其输出。 (请参见toarray,_process_toarray_args)
因此,您的问题可以简化为:np.zeros
为什么不分配足够的内存?
答案可能是lazy-initialization
和zero pages
。
Why does numpy.zeros takes up little space
Linux kernel: Role of zero page allocation at paging_init time
因此,矩阵中的所有零区域实际上都在同一个物理内存块中,并且只有对所有条目进行写操作才会迫使操作系统分配足够的物理内存。