稀疏矩阵 matlab 意外行为

sparse matrix matlab unexpected behavior

我正在创建一个稀疏矩阵

sp = sparse(I,J,Val,X,Y)

我的 Val 矩阵是个位矩阵。令我惊讶的是 sp 矩阵不仅仅包含零和一。我想发生这种情况是因为在某些情况下 IJ 中存在重复项。我的意思是 sp(1,1) 设置为 1 2 次,这样就变成了 2。

问题 1:我的假设是否正确? MATLAB 真的添加了它而不是覆盖该值吗?

问题 2:鉴于操纵 IJ 会非常麻烦,我们如何解决这个问题。我能想到的是使用 find (从而保证唯一性),然后再次使用 ones 重新创建矩阵。有更好的建议吗?

Question 1: Is my assumption true? Instead of overwriting the value, does Matlab really add it?

正确。如果您有重复的行和列值,每个值都有自己的值,MATLAB 会通过添加它们将它们全部聚合到相同的行和列位置。

This is clearly seen in the documentation 但作为一个可重现的示例,假设我有以下行和列位置及其在这些位置的关联值:

i = [6 6 6 5 10 10 9 9].';
j = [1 1 1 2 3 3 10 10].';
v = [100 202 173 305 410 550 323 121].';

请注意,这些是列向量,因为此形状是预期的输入。在更简洁的演示文稿中:

>> [i j v]

ans =

     6     1   100
     6     1   202
     6     1   173
     5     2   305
    10     3   410
    10     3   550
     9    10   323
     9    10   121

我们可以看到有三个值映射到位置 (6, 1),两个值映射到位置 (10, 3),最后两个值映射到位置 (9, 10)

通过创建稀疏矩阵并显示它,我们因此得到:

>> S = sparse(i,j,v)

S =

   (6,1)      475
   (5,2)      305
  (10,3)      960
   (9,10)     444

如您所见,映射到 (6, 1) 的三个值相加:100 + 202 + 173 = 475。您可以使用其他重复的行和列位置来验证这一点。


Question 2: How can we get around this, given that it would be very troublesome to manipulate I and J. Something I can think of, is to use find (thus guaranteeing uniqueness) and then recreate the matrix using ones once more. Any better suggestion?

如果您确实希望只有一个二进制矩阵,那么有两种可能的方法可以缓解这种情况。

第一种方法可能更适合您,正如您提到的那样,操作行和列的位置很麻烦,是创建您现在拥有的矩阵,然后将其转换为 logical,以便任何非零值设置为 1:

>> S = S ~= 0

S =

  10×10 sparse logical array

   (6,1)      1
   (5,2)      1
  (10,3)      1
   (9,10)     1

如果您要求矩阵的精度恢复到其原始 double 形式,请在转换为 logical:

后转换结果
>> S = double(S ~= 0)

S =

   (6,1)        1
   (5,2)        1
  (10,3)        1
   (9,10)       1

如果您愿意,第二种方法是处理行和列的位置,以便过滤掉所有非唯一的索引,然后为 val 创建一个 ones 的向量与唯一的行和列位置一样长。您可以使用 unique 函数来帮助您做到这一点。连接两列矩阵中的行和列位置,并指定要对 'rows' 进行操作。这意味着每一行都被视为输入而不是矩阵中的单个元素。找到唯一的行和列位置后,将它们用作创建稀疏矩阵的输入:

>> unique_vals = unique([i j], 'rows')

unique_vals =

     5     2
     6     1
     9    10
    10     3

>> vals = ones(size(unique_vals, 1));
>> S = sparse(unique_vals(:, 1), unique_vals(:, 2), vals)

S =

   (6,1)        1
   (5,2)        1
  (10,3)        1
   (9,10)       1