MATLAB: условное суммирование - PullRequest
3 голосов
/ 06 ноября 2011

У меня есть два массива следующей формы:

v1 = [ 1 2 3 4 5 6 7 8 9 ... ]
c2 = { 'a' 'a' 'a' 'b' 'b' 'c' 'c' 'c' 'c' ... }

(все значения приведены только в качестве примера, в реальных данных нельзя предположить шаблон. v1 и c2 имеют одинаковый размер)

Я хочу получить вектор, содержащий суммирование компонентов v1, соответствующих равным значениям в c2.В приведенном выше примере первый компонент результирующего вектора будет 1+2+3, второй 4+5 и т. Д.

Я знаю, что могу сделать это в цикле вида:

uni_c2 = unique(c2);
result = zeros(size(uni_c2));
for i = 1:numel(uni_c2)
     result(i) = sum( v1(strcmp(uni_c2(i),c2)) );
end 

Существует ли одна команда или векторизованный способ выполнения той же операции?

Ответы [ 3 ]

3 голосов
/ 06 ноября 2011

Вы можете сделать это в две строки:

[b, m, n] = unique(c2)
result = accumarray(n', v1)

Элементы результата соответствуют строкам в массиве ячеек b.

1 голос
/ 06 ноября 2011

Это векторизация, но плохая идея для очень больших векторов. Для некоторых задач «векторизованное» решение хуже, чем цикл for.

>> v1 = [ 1 2 3 4 5 6 7 8 9];
>> c2 = 'aaabbcccc'-'a'
c2 =
   0   0   0   1   1   2   2   2   2
>> N = repmat(c2',1,max(c2)-min(c2)+1) == repmat([min(c2):max(c2)],size(c2,2),1);
>> v1*N
ans =
    6    9   30
0 голосов
/ 06 ноября 2011

Я думаю, что очень общее (и векторизованное) решение выглядит примерно так:

v1 = [ 1 2 3 4 5 6 7 8 9  ]
c2 = { 'a' 'a' 'a' 'b' 'b' 'c' 'c' 'c' 'c'  }
uniqueValuesInC2 = unique(c2);
conditionalSumOfV1 = @(x)(sum(v1(strcmp(c2, x))));
result = cellfun(conditionalSumOfV1, uniqueValuesInC2)

Возможно, мое решение нуждается в небольшом объяснении неподготовленным глазом:

Итак, сначала вам нужно вычислить различные возможные значения в c2, что делается с помощью unique.

Функция conditionalSumOfV1 принимает аргумент x, она сравнивает каждый элемент в c2 с x и выбирает соответствующие элементы в v1 и суммирует их.

Наконец, cellfun сопоставим с конструкцией foreach в некоторых других языках: функция conditionalSum вычисляется для каждого значения в массиве ячеек, который вы предоставляете (в данном случае: каждое уникальное значение в c2) сохраняет его в выходном массиве. Для других типов контейнерных переменных (массивов, структур) MATLAB имеет эквивалентные foreach -подобные конструкции: arrayfun, structfun.

Это будет работать для содержимого c2, которое длиннее одного символа, и не требует большой операции repmat в качестве решения Stardt. У меня, однако, есть сомнения, когда дело доходит до длинных массивов, где c2 имеет только несколько повторяющихся значений, но я думаю, что это будет сложный случай для большинства алгоритмов. Если вы находитесь в таком случае, вам может понадобиться взглянуть на дополнительные выходные данные unique или написать свою собственную альтернативу unique (то есть написать for циклы, предпочтительно на скомпилированном языке / MEX).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...