2

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.

Cecilia
  • 4,512
  • 3
  • 32
  • 75

1 Answers1

4

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 convert L into indices to be used as first input to accumarray. 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 call accumarray once per column of M.
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • 1
    Of course! Matrix multiplication is summing rows. This works for me, but how should I clarify my question so that it will be more useful to future readers? – Cecilia Apr 27 '15 at 22:13
  • 2
    @Cecilia Actually the question is not so unclear; it's only long. I didn't understand everything initially because I have a tendency to read questions too fast. But it's all there (I'm going to edit my answer to remove that comnent, as it's no longer true and may be misleading). So my only suggestion would be to reduce question length a bit, _if_ it can be done without losing any meaning. BTW, it's great that you care for future readers. Some askers here seem to forget that! :-) – Luis Mendo Apr 27 '15 at 22:19