1

Suppose, I have the following matrix,

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

I want to create an array of 4 matrices, classified according to the column # 1.

For instance, the output should be like the following,

[ 
  2 3 4 5 6 7 8
  8 7 6 5 4 3 2

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

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

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

My target is to apply this Parzen function to each of them.


Is it something like the following?

function [retval] = bayes (train, test)

    classCounts = rows(unique(train(:,1)));
    pdfmx = ones(rows(test), classCounts);

    variance = 0.25;
    pdf = parzen(train(:,2:end), test(:,2:end), variance);

    for cl=1:classCounts
        clidx = train(:,1) == cl;
        mu(:,cl) = train(clidx,2:end);      
    end
    retval = mu;
endfunction

This code is generating the following error,

>> bayes(mat, mat)
error: bayes: A(I,J,...) = X: dimensions mismatch
error: called from
    bayes at line 11 column 12
>>
Community
  • 1
  • 1
user366312
  • 16,949
  • 65
  • 235
  • 452

1 Answers1

2

That's a classic job for accumarray. It outputs a cell array, but I recommend you to continue with a 3D-matrix.

%// data
A = [1   2   3   4   5   6   7   8
     2   3   4   5   6   7   8   1 
     3   4   5   6   7   8   1   2 
     4   5   6   7   8   1   2   3
     1   8   7   6   5   4   3   2
     2   7   6   5   4   3   2   9
     3   6   5   4   3   2   9   8 
     4   5   4   3   2   9   8   7]

%// input
groupid = A(:,1);      %// group identifier
rowidx = 1:size(A,1);  %// row index

%// accumarray
cellArray = accumarray(groupid(:),rowidx (:),[],@(x) {A(x,2:end)})

%// transform cell array to 3D-Matrix
threeDArray = cat(3,cellArray{:})

Explanation

What does accumarray?

  • It takes all elements of vals = rowidx with the same subs = groupid, groups it and performs an action.
  • As you want to perform an action on rows of a matrix and not a single vector, but vector input is required, you "trick" accumarray by actually introducing the row indices as input, which you than use within the function applied
  • A(x,2:end) means you take all rowidx with the same groupid stored in x and you use it to access your matrix A, you put {} around to get a cell array output

cellArray{1} =
     8     7     6     5     4     3     2
     2     3     4     5     6     7     8
cellArray{2} =
     7     6     5     4     3     2     9
     3     4     5     6     7     8     1
cellArray{3} =
     6     5     4     3     2     9     8
     4     5     6     7     8     1     2 
cellArray{4} =
     5     4     3     2     9     8     7
     5     6     7     8     1     2     3

threeDArray(:,:,1) =
     8     7     6     5     4     3     2
     2     3     4     5     6     7     8  
threeDArray(:,:,2) =
     7     6     5     4     3     2     9
     3     4     5     6     7     8     1
threeDArray(:,:,3) =
     6     5     4     3     2     9     8
     4     5     6     7     8     1     2
threeDArray(:,:,4) =
     5     4     3     2     9     8     7
     5     6     7     8     1     2     3

If the order of rows in the output is important, you need a "stable version" of accumarray (inspired by this answer:

%// stabilize accumarray
sz = max(groupid,[],1);
[~, I] = sort(groupid*cumprod([1,sz(1:end-1)]).');

%// stable accumarray
cellArray = accumarray(groupid(I,:),rowidx(I),[],@(x) {A(x,2:end)})

cellArray{1} =
     2     3     4     5     6     7     8
     8     7     6     5     4     3     2
cellArray{2} =
     3     4     5     6     7     8     1
     7     6     5     4     3     2     9
cellArray{3} =
     4     5     6     7     8     1     2
     6     5     4     3     2     9     8
cellArray{4} =
     5     6     7     8     1     2     3
     5     4     3     2     9     8     7

threeDArray(:,:,1) =
     2     3     4     5     6     7     8
     8     7     6     5     4     3     2
threeDArray(:,:,2) =
     3     4     5     6     7     8     1
     7     6     5     4     3     2     9
threeDArray(:,:,3) =
     4     5     6     7     8     1     2
     6     5     4     3     2     9     8
threeDArray(:,:,4) =
     5     6     7     8     1     2     3
     5     4     3     2     9     8     7
Community
  • 1
  • 1
Robert Seifert
  • 25,078
  • 11
  • 68
  • 113