группировка и суммирование (функции оценки) по значениям матрицы в Matlab

Многие потоки здесь показывают, что accumarray - это ответ в Matlab для группировки (и вычисления) значений по наборам индексов. Поскольку это работает быстро и хорошо, мне нужно иметь что-то подобное для больших (ND) полей данных.
Давайте рассмотрим пример: у нас есть вектор имен с (неуникальными) именами внутри и вектор данных доходов для разные проекты по столбцам

names=str2mat('Tom','Sarah','Tom','Max','Max','Jon');
earnings=[100 200 20;20 100 500;1 5 900; 100 200 200;200 200 0; 300 100 -250];

и теперь мы хотим вычислить суммы столбцов для каждого имени.
Хорошо, мы можем узнать индексы по

[namesuq,i1,i2]=unique(names,'rows')

но после этого очевидный звонок

accumarray(i2,earning)

не работает. Можно, конечно, использовать цикл for для уникальных имен или строк, но это может быть немного неэффективно. Есть ли идеи получше?
Кроме того, я попробовал

accumarray(i2,@(i)earnings(i,:))

но это не реализовано и приводит к

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

Спасибо за идеи.

Дополнения: спасибо eitan-t за его решение, которое отлично подходит для примера.
Так грустно, мой минимальный рабочий пример не показал всех потребностей: функция, которую я хочу применить, нуждается в целой строке или позже, возможно, в полной матрице, которую мне нужно сгруппировать по 3-му или даже более высокому измерению.

Может быть, чтобы было понятнее: подумайте о матрице M размером a x b x c, и каждая запись в a соответствует имени или около того. Моя потребность лучше всего описана, например, суммированием всех уникальных имен.
Наивное программирование было бы

nam=unique(names);
for ind=1:size(nam,2)
    N(ind,:,:)=sum(M(nam(ind)==names,:,:),1);
end

Это понятно? Есть ли решения для этого?


person Bastian Ebeling    schedule 27.08.2013    source источник
comment
возможный дубликат MATLAB находит и применяет функцию к значениям повторяющихся индексы   -  person Eitan T    schedule 27.08.2013


Ответы (1)


Основываясь на этом ответе, вы ищете следующее решение:

[namesuq, i1, i2] = unique(names, 'rows');
[c, r] = meshgrid(1:size(earnings, 2), i2);
y = accumarray([r(:), c(:)], earnings(:));

где строки соответствуют names(i1, :).

Пример

%// Sample input
names = str2mat('Tom', 'Sarah', 'Tom', 'Max', 'Max', 'Jon');
earnings = [100 200 20; 20 100 500; 1 5 900; 100 200 200; 200 200 0; 300 100 -250]

%// Sum along columns by names 
[namesuq, i1, i2] = unique(names, 'rows');
[c, r] = meshgrid(1:size(earnings, 2), i2);
y = accumarray([r(:), c(:)], earnings(:))

Итоговые суммы:

y =
   300   100  -250
   300   400   200
    20   100   500
   101   205   920

которые соответствуют names(i1, :):

ans =
    Jon  
    Max  
    Sarah
    Tom  
person Eitan T    schedule 27.08.2013
comment
Спасибо за быстрый ответ и извините за вопрос, на который уже ответили. Дальше я немного поторопился: есть ли еще шанс получить это без масштабирования индексации? У меня есть функция для применения, которая будет занимать целый столбец (что было непонятно из примера). - person Bastian Ebeling; 27.08.2013
comment
Вы имеете в виду, что хотите применить функцию к группе значений (например, применить ее к [100; 1] в первом столбце для Тома и т. д.)? Не могли бы вы дать более четкое описание того, что вы ожидаете получить? - person Eitan T; 27.08.2013
comment
Привет Эйтан, ты все еще читаешь? У тебя есть мое обновление? Предложения? Заранее спасибо. - person Bastian Ebeling; 29.08.2013
comment
@BastianEbeling Конечно, у меня просто не было времени перечитывать. Я сделаю все возможное, чтобы добраться до него сегодня! :) - person Eitan T; 29.08.2013