Как я могу создать массив матриц из одной матрицы, используя первый столбец в качестве индекса?

Предположим, у меня есть следующая матрица,

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

Я хочу создать массив из 4-х матриц, классифицированных по столбцу №1.

Например, вывод должен выглядеть следующим образом:

[ 
  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 
] 

Моя цель — применить эту функцию Парзена к каждому из них.


Это что-то вроде следующего?

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

Этот код генерирует следующую ошибку,

>> bayes(mat, mat)
error: bayes: A(I,J,...) = X: dimensions mismatch
error: called from
    bayes at line 11 column 12
>>

person user366312    schedule 06.11.2016    source источник


Ответы (1)


Это классическая работа для accumarray. Он выводит массив ячеек, но я рекомендую вам продолжить работу с 3D-матрицей.

%// 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{:})

Объяснение

Что делает accumarray?

  • Он берет все элементы vals = rowidx с одним и тем же subs = groupid, группирует их и выполняет действие.
  • Поскольку вы хотите выполнить действие со строками матрицы, а не с одним вектором, а требуется ввод вектора, вы «обманываете» accumarray, фактически вводя индексы строк в качестве входных данных, которые вы затем используете в применяемой функции.
  • A(x,2:end) означает, что вы берете все rowidx с одним и тем же groupid, хранящимся в x, и используете его для доступа к вашей матрице A, вы помещаете {} вокруг, чтобы получить вывод массива ячеек

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

Если порядок строк в выводе важен, вам нужна «стабильная версия» accumarray (вдохновленная этот ответ:

%// 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
person thewaywewalk    schedule 06.11.2016
comment
cellArray = accumarray(subs(:),vals(:),[],@(x) {A(x,2:end)}) это очень трудно понять. - person user366312; 06.11.2016
comment
@anonymous взгляните на мою правку, вместе с документом теперь должно быть понятнее - person thewaywewalk; 07.11.2016