MATLAB Accumarray взвешенное среднее

Поэтому в настоящее время я использую «accumarray», чтобы найти средние значения диапазона чисел, которые соответствуют совпадающим идентификаторам. Пример ввода:

ID----Value
1     215
1     336
1     123
2     111
2     246
2     851

Мой текущий код находит невзвешенное среднее вышеперечисленных значений, используя идентификатор в качестве «разделителя», поэтому я не получаю среднее значение для всех значений вместе как одно число, а скорее отдельные результаты только для значений, которые имеют соответствующие идентификаторы . Экс выход:

ID----Value
1     224.66
2     402.66

Для этого я использую этот код:

[ID, ~, Groups] = unique(StarData2(:,1),'stable');
app = accumarray(Groups, StarData2(:,2), [], @mean);

При этом StarData2 является входом функции. Это отлично работает для моих целей до сих пор, мне нужно знать, можно ли сделать accumarray, чтобы дать мне средневзвешенное значение, чтобы каждой точке в приложении (до того, как среднее значение было найдено) можно было присвоить вес или что @mean может быть заменена функцией, которая может достичь этого. Новый ввод будет выглядеть так:

ID----Value----Weight
1     215     12
1     336     17
1     123     11
2     111     6
2     246     20
2     851     18

Новый код должен вычислять сумму(значение(i)*вес(i))/сумму(вес) вместо стандартного среднего значения. Спасибо за любую помощь.


person ImmortalxR    schedule 01.04.2014    source источник


Ответы (4)


Вы можете использовать индекс строки как "vals" (второй ввод на accumarray) и определите собственную функцию, которая вычисляет средневзвешенное значение группа данных:

Weights = data(:,3); Vals = data(:,2); % pick your columns here
WeightedMeanFcn = @(ii) sum(Vals(ii).*Weights(ii))/sum(Weights(ii));
wmeans = accumarray(Groups, 1:numel(Groups), [], WeightedMeanFcn)

Демонстрация

Начиная с data (новый ввод с вашими весами) и вашей команды unique:

data = [1,215,12; 1,336,17; 1,123,11; 2,111,6; 2,246,20; 2,851,18];
[ID, ~, Groups] = unique(data(:,1),'stable');

Использование accumarray выглядит следующим образом (переопределяйте WeightedMeanFcn каждый раз, когда вы меняете data!):

>> Weights = data(:,3); Vals = data(:,2); % pick your columns here
>> WeightedMeanFcn = @(ii) sum(Vals(ii).*Weights(ii))/sum(Weights(ii));
>> app = accumarray(Groups, 1:numel(Groups), [], WeightedMeanFcn)
app =
  241.1250
  475.0909

Проверка вручную, с первой группой:

ig = 1;
sum(data(Groups==ig,2).*data(Groups==ig,3))/sum(data(Groups==ig,3))
ans =
  241.1250
person chappjc    schedule 01.04.2014
comment
ПРИМЕЧАНИЕ. data не является входом для WeightedMeanFcn. Он должен быть определен до определения WeightedMeanFcn! Затем он будет захвачен анонимным функция. - person chappjc; 01.04.2014
comment
Это хорошо, но я получаю неправильный вывод, поэтому я обновляю OP, чтобы показать точный стиль ввода и вывода. - person ImmortalxR; 01.04.2014
comment
@ImmortalxR WeightedMeanFcn = @(x) sum(StarData4(x,5).*StarData4(x,6))/sum(StarData4(x,6)). Я изменяю свой код, чтобы веса и значения были более явными, а не столбцами. - person chappjc; 02.04.2014
comment
Удивительно! это прекрасно работает. Я пытался внести аналогичные изменения сам, но это не сработало, но это здорово! - person ImmortalxR; 02.04.2014
comment
@ImmortalxR Отлично! Просто обратите внимание на то, что я сказал о необходимости переопределять анонимную функцию каждый раз, когда изменяется массив данных, поскольку функция сохраняет массив data внутри, когда он определен. - person chappjc; 02.04.2014

Вместо использования accumarray вы можете довольно легко напрямую вычислить средневзвешенное значение или многие другие функции:

nIDs = length(unique(ID));
WeightedMean = zeros(nIDs, 1);

for ii = 1:nIDs
    iID = (ID == ii);
    WeightedMean(ii) = (Value(iID)' * Weight(iID)) / sum(Weight(iID));
end

Есть ли конкретная причина, по которой вы хотите сделать это через accumarray?

person buzjwa    schedule 01.04.2014

@Naveh - обычно рекомендуется избегать использования циклов в Matlab. В частности, если у вас есть большой набор данных со многими группами, это может быть очень медленным.

Использование accumarray - это путь, но определение функции индексов, как это было предложено @chappjc, подвержено ошибкам, поскольку для захвата анонимной функцией вы должны убедиться, что

данные не являются входными данными для WeightedMeanFcn. Он должен быть определен перед определением WeightedMeanFcn,

как говорит @chappjc в своем комментарии.

Небольшая модификация для решения этой проблемы заключается в использовании accumarray дважды:

Weights = data(:,3); Vals = data(:,2); % pick your columns here    
app = accumarray(Groups, Weights.*vals, [], @mean)./accumarray(Groups, Weights, [], @mean);

Иногда вам может понадобиться заменить аргумент [] размером требуемого вывода.

person user3315957    schedule 10.09.2017
comment
Только одно предложение: используйте @sum вместо @mean. - person gnovice; 11.09.2017

Вы пытаетесь вычислить не взвешенное среднее, а скорее взвешенную гистограмму.
Существует реализация взвешенной гистограммы mex, которую можно найти здесь. Тем не менее, accumarray - это безопасный способ.

person Shai    schedule 03.04.2014