Matlab:使用Find()出现内存错误,为什么?

时间:2014-12-04 20:48:00

标签: matlab

我有一个稀疏矩阵M(290k,230k),大小约为640MB(通过whos检查)。

以下说明:

find(M > 0 & M<=10);

产生“Out of memory”错误,我不明白为什么,仍然有足够的内存可用,并且值在0到10之间的索引列表不能大于矩阵本身的大小。我错过了什么吗?我想是的。

编辑:

我假设M > 0M<=10之前执行(正如在其他编程语言中发生的那样),但我认为我错了,实际上:

temp = find(M > 0)
find(M(temp) < 10)

不会产生任何错误,但我无法获得M的原始值。

因为我的最终目标是将所有值设为0&lt; 10,我改写了我的问题。

拥有一个很大且非常稀疏的矩阵M(290k,230k)如何将所有值设置为0&lt; 10不使用慢速循环?

编辑2,回复@ AnderBiguri的代码:

我已经尝试过你的代码,没有修改Mnew =稀疏(零(大小(M)))我得到“内存不足”,但这是可以理解的。奇怪的是,即使你的代码有意义,我也会得到“订阅分配维度不匹配”。在这一行:

Mnew(ii(notdelete),jj(notdelete))=nz(notdelete);

我不明白为什么,这是在作业之前whos的结果:

  

ii 39701898x1 317615184双
  jj 39701898x1 317615184双
  M 290621x232537 1860320双稀叉   Mnew 290621x232537 637090672双稀叉   notdelete 39701898x1 39701898逻辑
  nz 39701898x1 317615184双

一切对我都有意义,因为M的非零元素的数量是39701898.如果我在一个小的测试矩阵上尝试你的代码,一切都按预期工作,原始矩阵我得到了那个错误。有没有办法调试这种错误?

编辑3:重现错误的一些代码

R = sprand(29062,23253,5.8748e-04);
[ii,jj,nz]=find(R);
notdelete=nz>0.5;
R2=sparse( size(R,1), size(R,2) );
R2(ii(notdelete),jj(notdelete))=nz(notdelete);

1 个答案:

答案 0 :(得分:4)

问题在于M<=10

尝试:

M=sparse(eye(3))
M<=10

ans =

   (1,1)        1
   (2,1)        1
   (3,1)        1
   (1,2)        1
   (2,2)        1
   (3,2)        1
   (1,3)        1
   (2,3)        1
   (3,3)        1

恭喜!现在你有一个完全填充的稀疏矩阵!你现在正在使用完整矩阵的内存+非零条目索引的内存!这就是崩溃的原因。我建议您使用不同的方法来搜索您的解决方案。

因此,如果要删除小于0的值,可以执行以下操作:

% Example matrix
M=sparse(diag([1 11 4]))
sizeM=size(M);

% findnonzero elements and indexes
[ii,jj,nz]=find(M);

% Delete it if you are worried about memory
clear M

% Get the ones you want to keep
notdelete=nz>10;

% Create a new matrix with those
Mnew=sparse(sizeM);


indx=sub2ind(sizeM,ii(notdelete),jj(notdelete));
Mnew(indx)=nz(notdelete);

此代码的工作原理:

我所做的是描述备用矩阵M,因为内部描述了稀疏矩阵:非零值(iijj)的索引和值本身, nz

然后我找到遵循规则的非零值并且你想要保持(你可以做相反的事情而不是逻辑但是我决定这样做)。您要保留的是nz>10。如果您在Matlab中执行该操作,它将为您提供一个逻辑数组,其中1位于您要保留的位置,0位于您不存在的位置。

然后,创建一个空的备用矩阵(实际上我在那里有一个错误,你在下面的评论中正确地发现并纠正了它)。空白的Matrix充满了您要保留的nz,因此nz(notdelete)。同样,为了访问矩阵,只需要使用这些有用元素的索引,因此ii(notdelete),jj(notdelete)。我希望现在更清楚了


但是,请确保您了解自己在做什么。你陈述了

  

我认为M>在M <= 10之前执行0(在其他情况下发生)   编程语言)但我认为我错了

实际上M> 0在M <= 10之前执行。从左到右执行适用于其他编程语言。但是,您所做的是(M>0) & (M<=10),因此&的左右部分都需要在&之前进行评估。实际上,左边的一个将首先被评估,保存在一个辅助的内部变量中,但是然后右边的部分将被执行并保存到另一个辅助内部变量中,所以最后逻辑and可以应用于这两个辅助变量。