稀疏矩阵 matlab 意外行为
sparse matrix matlab unexpected behavior
我正在创建一个稀疏矩阵
sp = sparse(I,J,Val,X,Y)
我的 Val
矩阵是个位矩阵。令我惊讶的是 sp
矩阵不仅仅包含零和一。我想发生这种情况是因为在某些情况下 I
、J
中存在重复项。我的意思是 sp(1,1)
设置为 1 2 次,这样就变成了 2。
问题 1:我的假设是否正确? MATLAB 真的添加了它而不是覆盖该值吗?
问题 2:鉴于操纵 I
和 J
会非常麻烦,我们如何解决这个问题。我能想到的是使用 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
我正在创建一个稀疏矩阵
sp = sparse(I,J,Val,X,Y)
我的 Val
矩阵是个位矩阵。令我惊讶的是 sp
矩阵不仅仅包含零和一。我想发生这种情况是因为在某些情况下 I
、J
中存在重复项。我的意思是 sp(1,1)
设置为 1 2 次,这样就变成了 2。
问题 1:我的假设是否正确? MATLAB 真的添加了它而不是覆盖该值吗?
问题 2:鉴于操纵 I
和 J
会非常麻烦,我们如何解决这个问题。我能想到的是使用 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