A.Rainer
A.Rainer

Reputation: 719

calculate the number of shared values in a matrix

I have a 19 x 39 double M containing data for 19 network nodes in 39 different network configurations. Each column (i.e., each configuration) shows how which of these nodes group together into a network. If they belong to the same network, they will have the same value. The value also indicates how many networks there are. For instance, M could look like this:

1 1 1
1 2 2
3 2 1
1 2 2
2 3 2
2 3 3
2 3 3
1 3 3
1 2 2
2 1 2
1 1 3
1 1 1
2 2 1
1 2 2
2 2 2
2 2 3
3 1 3
2 1 1
2 3 1

This means that for column 1 (or configuration 1) there are three networks in this one configuration: network 1 containing nodes 1, 2, 4, 8, 9, 11, 12, 14; network 2 containing nodes 5, 6, 7, 10, 13, 15, 16, 18, 19; network 3 containing nodes 3, 17. Now, I want to calculate across 39 configurations (or columns) the number of the times each node belongs to the same network with each remaining node. In this example, node 1 belong to the same network with node 2 once while node 4 and 9 belong to the same network 3 times. I imagine the output would be a 19 x 19 matrix with each cell indicating how many times the node from the y axis is in the same network with the node in the x axis. The diagonal line is then 39 (as each node belong to the same network with itself for each configuration). Does anyone have a suggestion how to do this efficiently?

Upvotes: 3

Views: 66

Answers (1)

Suever
Suever

Reputation: 65430

You should be able to use bsxfun to check the equality of the matrix a with a permuted version of a. You can then sum across the second dimension to give you the number of co-occurances of two nodes in a given network and squeeze the result to get a 2D matrix

squeeze(sum(bsxfun(@eq, a, permute(a, [3 2 1])), 2))

The row/column of a given element in the output correspond to the number of times that the two nodes were in the same group.

As a simple example

a = [1 1 1
     1 2 1;
     2 2 1];

b = squeeze(sum(bsxfun(@eq, a, permute(a, [3 2 1])), 2))

% 3     2     1
% 2     3     2
% 1     2     3

From this, nodes 1 and 2, b(1,2), appeared in the same group 2 times (networks 1 and 3). Nodes 1 and 3, b(1,3) appeared in the same network once (network 3). Nodes 2 and 3, b(2,3), appeared in the same network twice (networks 2 and 3).

If you are using MATLAB R2016b or newer this can be simplified to

squeeze(sum(a == permute(a, [3 2 1]), 2));

An attempt at an explanation

Rather than considering the entire matrix of networks, let's first consider just the first network. We want to compare the group assigned to each node with the group assigned to every other node. We can create that matrix using bsxfun

tmp = bsxfun(@eq, a(:,1), a(:,1).')

% 1     1     0
% 1     1     0
% 0     0     1

Now if we did this for each network (column) of a we would get N of these matrix.

% Create a 3D matrix to hold co-occurance data
counts = zeros(size(a, 1), size(a, 1), size(a, 2));

for k = 1:size(a, 2)
    counts(:,:,k) = bsxfun(@eq, a(:,k), a(:,k).');
end

% Now count how many times two nodes were placed in the same group
nSameGroup = sum(counts, 3);

While this loop works, we can instead reshape the third input to bsxfun a little bit (using permute) such that it will create the counts matrix automatically.

tmp = bsxfun(@eq, a, permute(a, [3 2 1]))
%   tmp(:,:,1) =
%        1     1     1
%        1     0     1
%        0     0     1
%   tmp(:,:,2) =
%        1     0     1
%        1     1     1
%        0     1     1
%   tmp(:,:,3) =
%        0     0     1
%        0     1     1
%        1     1     1  

And then we sum along the second dimension to compute the number of co-occurrences and squeeze the result to get a 2D matrix.

squeeze(sum(tmp, 2))
% 3     2     1
% 2     3     2
% 1     2     3     

Upvotes: 3

Related Questions