Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I go through the columns of a matrix in matlab and add them each to a specific column of a sum matrix in matlab?

Supose there is a Matrix

A =

 1     3     2    4
 4     2     5    8
 6     1     4    9

and I have a Vector containing the "class" of each column of this matrix for example

v = [1 , 1 , 2 , 3]

How can I sum the columns of the matrix to a new matrix as column vectors each to the column of their class? In this example columns 1 and 2 of A would added to the first column of the new matrix, column 2 to the 3 to the 2nd, column 4 the the 3rd.

Like

SUM =

4    2    4
6    5    8
7    4    9

Is this possible without loops?

like image 551
I_like_foxes Avatar asked Dec 25 '22 20:12

I_like_foxes


2 Answers

One of the perfect scenarios to combine the powers of accumarray and bsxfun -

%// Since we are to accumulate columns, first step would be to transpose A
At = A.'  %//'

%// Create a vector of linear IDs for use with ACCUMARRAY later on
idx = bsxfun(@plus,v(:),[0:size(A,1)-1]*max(v))

%// Use ACCUMARRAY to accumulate rows from At, i.e. columns from A based on the IDs
out = reshape(accumarray(idx(:),At(:)),[],size(A,1)).'

Sample run -

A =
     1     3     2     4     6     0
     4     2     5     8     9     2
     6     1     4     9     8     9
v =
     1     1     2     3     3     2
out =
     4     2    10
     6     7    17
     7    13    17
like image 66
Divakar Avatar answered Dec 28 '22 23:12

Divakar


An alternative with accumarray in 2D. Generate a grid with the vector v and then apply accumarray:

A = A.';

v = [1 1 2 3]; 

[X, Y] = ndgrid(v,1:size(A,2));

Here X and Y look like this:

X =

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


Y =

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

Then apply accumarray:

B=accumarray([X(:) Y(:)],A(:)),

SUM = B.'

SUM =

     4     2     4
     6     5     8
     7     4     9

As you see, using [X(:) Y(:)] create the following array:

ans =

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

in which the vector v containing the "class" is replicated 3 times since there are 3 unique classes that are to be summed up together.

EDIT:

As pointed out by knedlsepp you can get rid of the transpose to A and B like so:

[X2, Y2] = ndgrid(1:size(A,1),v);

B = accumarray([X2(:) Y2(:)],A(:))

which ends up doing the same. I find it a bit more easier to visualize with the transposes but that gives the same result.

like image 30
Benoit_11 Avatar answered Dec 28 '22 23:12

Benoit_11