问题
Can I sum rows or columns over several indices without using a for loop?
I have an n by n matrix, M
, that represents the co-occurrence of vocabulary terms where n is the length of the vocabulary.
I also have a n by n logical mask, L
, which represents the pairs of vocabulary where the pair has the form (singular, plural). For example, in pseudo-code, L('octopus', 'octopuses') = True
I want to add the entries in M
for any pair which contains a plural to entry for the pair that contains the corresponding singular. For example, in pseudo-code, M_sum('octopus', 'swim') = M('octopus', 'swim') + M('octopuses', 'swim')
;
To illustrate what I've tried so far, let's use the following toy data.
vocabulary = {'octopus', 'octopuses', 'swim'};
% The co-occurrence matrix is symmetric
M = [0, 9, 3;
9, 0, 1;
3, 1, 0;];
% This example has only one plural singular pair
L = [0, 1, 0;
0, 0, 0;
0, 0, 0;];
To find the singular to plural correspondence, I can use find
[singular, plural] = find(L == 1);
If there is only one plural for each singular, summing the rows or columns is simple
M_sum = M;
M_sum(singular, :) = M_sum(singular, :) + M(plural, :);
M_sum(:, singular) = M_sum(:, singular) + M(:, plural);
% Remove diagonal entries
M_sum(eye(size(M))==1) = 0;
However, if there are several plurals that correspond to one singular, this approach cannot be used.
For example,
vocabulary = {'octopus', 'octopuses', 'octopi', 'swim'};
M = [0, 9, 5, 3;
9, 0, 7, 1;
5, 7, 0, 11;
3, 1, 11, 0;];
L = [0, 1, 1, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;];
The correct answer should be
M_sum = [0, 16, 12, 15;
16, 0, 7, 1;
12, 7, 0, 11;
15, 1, 11, 0;];
But using the above method returns
M_sum = [0, 16, 5, 14;
16, 0, 7, 1;
5, 7, 0, 11;
14, 1, 11, 0;];
Basically, M_sum(singular, :) = M_sum(singular, :) + M(plural, :);
only uses the last plural
index.
I think that I need to use accumarray here, but I'm having some trouble formulating the correct statement because I have two indices, plural
and singular
. If accumarray
is not the correct approach, other solutions are also welcome.
回答1:
Try this:
M_sum = (L + eye(size(L,1)))*M;
M_sum = triu(M_sum, 1);
M_sum = M_sum + M_sum.';
This works because you already have matrix L
, so matrix multiplication can be used to select and sum the rows of M
.
Using accumarray
here would have two drawbacks:
- You'd need to apply
find
to convertL
into indices to be used as first input toaccumarray
. So one more step. accumarray
can only sum numbers, not row vectors (its second input can only be a column vector, not a matrix). So you'd need to callaccumarray
once per column ofM
.
来源:https://stackoverflow.com/questions/29906059/summing-rows-by-index-using-accumarray