2 столбца в поле VAL accmarray - Matlab - PullRequest
1 голос
/ 02 ноября 2011

Мне не очень удобно использовать функцию accmarray в Matlab, хотя я начал ценить ее возможности!Мне было интересно, смогу ли я ввести 2 столбца в поле VAL функции accmarray.Пожалуйста, смотрите -

sz = 3  ; % num_rows for each ID
mat1 = [1 20 ; 1 40 ; 1 50 ; 2 10 ; 2 100 ; 2 110] ; % Col1 is ID, Col2 is Value
idx  = [30 1000 ; 30 1200 ; 30 1500 ; 30 1000 ; 30 1200 ; 30 1500 ] ; 
% col1: index ID, col2: value

mat1 - это возвращение идентификатора, в то время как idx - возвращение индекса.Для простоты возвращаемые idx повторяются, чтобы соответствовать mat1.Все идентификаторы в mat1 имеют одинаковые строки.Даже idx имеет одинаковые строки.

[~,~,n] = unique(mat1(:,1), 'rows', 'last') ;
fncovariance = @(x,y) (x.*y)/sz ;
accumarray(n, [x(:,2) y(:,2)], [], fncovariance) % --> FAILS as VAL is not-vector!

Вы видите, что я пытаюсь вычислить ковариацию (cov (x, y, 1)), но не могу использовать функцию Matlab напрямую, так как у mat1 есть идентификаторы, и мне нужноковариация для каждого идентификатора относительно индекса.

Ansmat:

    1 2444.4
    2 7888.9

1 Ответ

0 голосов
/ 02 ноября 2011

Краткий ответ - нет. В справке accumarray() ключевая часть:

"VAL должен быть числовым, логическим или символьным вектором одинаковой длины как количество строк в SUBS. VAL также может быть скаляром, значение которого повторяется для всех рядов SUBS. "

Это означает, что вы даже не можете подделать его с помощью ячеек.

Однако, если вы поместите идентификаторы в их собственную индексную переменную, а затем измените свои данные таким образом, чтобы данные, соответствующие различным идентификаторам, находились в разных столбцах, эта проблема может быть эффективно обработана с помощью bsxfun(). Для справки я также включил матричный математический метод, простой циклический метод for, использующий cov(), и метод cellfun(), использующий пользовательскую функцию fncovariance() (обратите внимание, я изменил его по сравнению с вашим выше).

fncovariance = @(x,y) mean(x.*y) - mean(x)*mean(y);

IDs = unique(mat1(:,1));
ret = reshape(mat1(:,2), sz, length(IDs));
idx = idx(1:sz, 2);
% bsxfun method
mean(bsxfun(@times, ret, idx)) - bsxfun(@times, mean(ret), mean(idx))
% matrix math
idx' * ret / length(idx) - mean(ret)*mean(idx)
% for loop method
id_cov = zeros(1, length(IDs));
for i=1:length(IDs)
    tmp = cov(ret(:,i), idx, 1);
    id_cov(i) = tmp(2,1);
end
id_cov
% cellfun method
ret_cell = num2cell(ret, 1);
idx_cell = num2cell(repmat(idx, 1, length(IDs)), 1);
cellfun(fncovariance, ret_cell, idx_cell)

Если вы смоделируете еще несколько данных и время этими разными методами, самый быстрый способ будет bsxfun():

sz    = 10;
n_ids = 100;

IDs = 1:n_ids;
ret = randi(1000, sz, n_ids);
idx = randi(1000, sz, 1);
Elapsed time is 0.001292 seconds.
Elapsed time is 0.001523 seconds.
Elapsed time is 0.009625 seconds.
Elapsed time is 0.011454 seconds.

Последний вариант, который может вас заинтересовать, - это функция grpstats() в наборе инструментов статистики, которая позволяет выкинуть произвольную статистику, основанную на переменной группировки.

...