Есть ли accumarray (), который принимает матрицу как `val`? - PullRequest
12 голосов
/ 04 декабря 2010

accumarray () 'val аргумент должен быть вектором.В моем случае мне нужны столбцы матрицы для суммирования (или усреднения).Есть ли функция или метод для достижения этой цели?

То, что я сейчас делаю, находится в цикле for. Я суммирую значения столбцов отдельно:

for iCol = 1:nCols
    means(:,iCol) = accumarray(labels', X(:,iCol));
end

Ответы [ 2 ]

9 голосов
/ 04 декабря 2010

Одним из решений является репликация индексов строк в labels и добавление еще одного столбца индексов столбцов.Затем вы можете изменить X в вектор-столбец и применить accumarray один раз:

labels = [repmat(labels(:),nCols,1) ...            % Replicate the row indices
          kron(1:nCols,ones(1,numel(labels))).'];  % Create column indices
totals = accumarray(labels,X(:));  % I used "totals" instead of "means"


Как это работает ...

A = accumarray(subs,val) для вектора-столбца subs и вектора val работает путем добавления числа в val(i) к итогу в строке subs(i) в векторе выходного столбца A.Однако subs может содержать не только индексы строк.Он может содержать индексы индексов для нескольких измерений, которым можно присвоить значения в выходных данных.Эта функция позволяет обрабатывать ввод val, который является матрицей, а не вектором.

Во-первых, вход для val может быть преобразован в вектор столбца с помощью оператора двоеточия X(:).Затем, чтобы отслеживать, какой столбец в выходных данных должен содержать значения в X(:), мы можем изменить ввод subs, добавив дополнительный индекс столбца.Чтобы проиллюстрировать, как это работает, я буду использовать эти примеры входных данных:

labels = [3; 1; 1];
X = [1 2 3; ...
     4 5 6; ...
     7 8 9];
nCols = 3

А вот как выглядят переменные в приведенном выше коде:

labels = 3 1    X(:) = 1    totals = 11 13 15
         1 1           4              0  0  0
         1 1           7              1  2  3
         3 2           2
         1 2           5
         1 2           8
         3 3           3
         1 3           6
         1 3           9

Обратите внимание, дляНапример, значения 1 4 7, которые изначально были в первом столбце X, будут накапливаться только в первом столбце выходных данных, что обозначено значениями в первых трех строках второго столбца labels.Результирующий вывод должен быть таким же, как и при использовании кода в вопросе, где вы перебираете каждый столбец для выполнения накопления.

1 голос
/ 12 ноября 2018

Возможно, более интуитивный (возможно, более эффективный) способ заимствован из Ответы MATLAB (исходный ответ предполагает ввод основных данных столбца, поэтому я перенес их):

[xx, yy] = ndgrid(labels,1:size(X, 1));
totals = accumarray([yy(:) xx(:) ], reshape(X.', 1, []));

Пример:

X = [1 2 3 4; 5 6 7 8];
labels = [2; 1; 3; 1];

дает totals = [6 1 3; 14 5 7].

Если вы хотите сделать это построчно, тогда нет необходимости транспонировать, просто:

[xx, yy] = ndgrid(labels,1:size(X, 2));
totals = accumarray([xx(:) yy(:)], X(:));
...