Python 为什么我的NumPy阵列占用的内存比它应该占用的要少?

Python 为什么我的NumPy阵列占用的内存比它应该占用的要少?,python,numpy,Python,Numpy,我正在处理大型矩阵,例如。我重新构造了在线文件,使其与页面上提到的维度相匹配(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

我正在处理大型矩阵,例如。我重新构造了在线文件,使其与页面上提到的维度相匹配(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检查进程时,内存消耗仅显示约7GB,尽管保留了约32GB的虚拟内存

起初,我认为这可能是由于pandas reader或
scipy.sparse
包的一些“效率技巧”,以避免内存消耗激增
但即使在我调用PCA函数之后,它也不会将活动内存消耗增加到它应该增加的程度。 请注意,调用
mat.nbytes
返回准确的估计量,因此NumPy似乎至少知道数据


(PCA代码供参考:)

请注意,尽管fbpca使用随机算法,并且我只计算前三个分量,但仍然执行输入矩阵与(小得多的)随机矩阵的(单个但完整的)矩阵乘法。本质上,它仍然必须至少访问一次输入矩阵中的每个元素


最后一句话也使这与我发现的帖子略有不同,比如,因为在那篇帖子中,元素从未真正被访问过。

我认为你的问题在于
todense()
调用,它使用
np.asmatrix(self.toarray(order=order,out=out))
toarray
使用
np.zero
创建其输出。(见,)

所以你的问题可以归结为:为什么
np.zero
没有分配足够的内存

答案可能是
延迟初始化
零页



因此,矩阵中的所有零区域实际上都在同一个物理内存块中,只有写入所有条目才会迫使操作系统分配足够的物理内存。

7GB+32GB=39GB,足以容纳数据。为什么您要假设进程没有存储32GB的数据?它为整个大小保留虚拟内存,但从来没有实际“直接使用”它。在我看来,一旦我乘以矩阵,活动消耗量应该在27 GB左右,因为这会访问每个元素。我想你误解了虚拟内存是什么。你想详细说明一下吗?我的意思是,当我乘以矩阵时,它应该仍然显示为活跃消费,对吗?这可能是一个开始阅读它的好地方:。虚拟并不意味着进程没有使用内存,它只是意味着分配给进程的内存目前不在物理ram中。当然,要执行矩阵乘法,必须先加载到ram,然后再加载到CPU,但numpy一次只能乘法几个元素。操作系统知道的足够多,不会将整个阵列加载到ram中,只加载当前正在操作的部分。因此,您的意思是稀疏矩阵的密度(即非零元素的数量)应该会对最初消耗的内存产生影响。。。非常有趣,我将尝试用稍微不同的矩阵变体来测试这一点。问题仍然是,当我对矩阵乘法进行传递时,为什么它不会分配内存。@Denninger不仅仅是零的数量,而是只包含零的块/页的数量。意思是长的连续序列zeros@dennlinger在迭代数据时是否修改值?如果您只阅读,则应保留零页。您可以尝试使用随机非零值覆盖整个矩阵,然后再次检查RAM消耗。如果需要,fbpca的计算似乎会创建行/列的本地副本,但决不会覆盖原始矩阵。因此,零页似乎仍然有效,这大大减少了内存消耗。
from fbpca import pca
result = pca(mat, k=3, raw=False, n_iter=3)