MATLAB累加数组加权平均

6

目前我正在使用'accumarray'函数来查找与匹配ID相对应的一系列数字范围的平均值。例如,输入:

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

我的当前代码通过使用ID作为“分隔符”来查找上述值的无权平均值,以便我不会得到所有值的平均值作为一个数字,而是仅针对具有相应ID的值分别得到结果。

例如输出:

ID----Value
1     224.66
2     402.66

为了实现这个目标,我正在使用以下代码:
[ID, ~, Groups] = unique(StarData2(:,1),'stable');
app = accumarray(Groups, StarData2(:,2), [], @mean);

使用StarData2作为函数的输入。到目前为止,这对我的目的完美地工作,但我需要知道是否可以使accumarray给我加权平均值,以便在找到平均值之前可以为app中的每个点分配一个权重,或者@mean可以被替换为可以实现此功能的函数。新的输入将如下所示:

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

新代码必须执行sum(val(i)*weight(i))/sum(weight)而不是标准均值。感谢您的任何帮助。
4个回答

7
你可以使用行索引作为“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的用法如下(每次更改data时重新定义WeightedMeanFcn!):
>> 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

注意:data 不是 WeightedMeanFcn 的输入。它必须在定义 WeightedMeanFcn 之前定义!然后它将被匿名函数所捕获 - chappjc
这很好,但我得到的输出是错误的,所以我正在更新OP以显示输入和输出的确切样式。 - ImmortalxR
1
@ImmortalxR WeightedMeanFcn = @(x) sum(StarData4(x,5).*StarData4(x,6))/sum(StarData4(x,6))。我正在修改我的代码,使权重和值更加明确,而不是列。 - chappjc
1
太棒了!这个很好用。我之前尝试过做类似的修改,但是不起作用,但这个真的很好! - ImmortalxR
@ImmortalxR 很好!请注意我的话,每次数据数组更改时都必须重新定义匿名函数,因为该函数在定义时内部存储“data”数组。 - chappjc

1

@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);

有时候,您可能需要用所需输出的大小替换[]参数。

只有一个建议:使用@sum而不是@mean - gnovice

1

不必使用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实现此操作?


-1
你想计算的不是加权平均值,而是加权直方图。
可以在这里找到加权直方图的mex实现here。然而,使用accumarray 是一个安全的选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接