MATLAB查找并应用函数到重复索引的值

时间:2013-04-18 15:20:10

标签: matlab matrix mean

我有一个352x11矩阵,由第1列索引,有10个数据点。一些索引值重复出现。我想找到重复的指数并计算重复试验的平均数据点(如果可能的话,避免循环)。

例如,

x =

   26   77.5700   17.9735   32.7200
   27   40.5887   16.6100   31.5800
   28   60.4734   18.5397   33.6200
   28   35.6484   27.2000   54.8000
   29   95.3448   19.0000   37.7300
   30   82.7273   30.4394   39.1400

最终:

ans =

   26   77.5700   17.9735   32.7200
   27   40.5887   16.6100   31.5800
   28   48.0609   22.8699   44.2150
   29   95.3448   19.0000   37.7300
   30   82.7273   30.4394   39.1400

我在想是否使用

J = find(diff(x(:,1))==0);

找到重复值的位置,然后我可以将函数应用到x的相应位置,但是我从哪里开始?

4 个答案:

答案 0 :(得分:6)

更通用的方法是使用unique来查找唯一索引值:

[U, ix, iu] = unique(x(:, 1));

然后accumarray

[c, r] = meshgrid(1:size(x, 2), iu);
y = accumarray([r(:), c(:)], x(:), [], @mean);

解释

要处理的输入值实际上是accumarray second 参数。

accumarray第一个参数是一个矩阵,每一行是(累积的)输出矩阵中的一组索引,它对应于来自匹配行的一个值。作为第二个参数给出的矢量。

将输出视为单元阵列。第二个参数是输入值,第一个参数中的每一行告诉输出矩阵accumarray的哪个单元应该存储相应的输入值。输出“单元格数组”完成后,函数(在我们的例子中为mean)将应用于每个单元格。

实施例

以下是一个较小矩阵的简短示例:

x = [27, 10, 8;
     28, 20, 10;
     28, 30, 50];

我们通过以下方式找到唯一值:

[U, ix, iu] = unique(x(:, 1));

向量U存储唯一值,iu表示与每行关联的值的哪个索引(请注意,此解决方案中我们没有使用ix)。在我们的例子中,我们得到了:

U = 
    27
    28

iu =
    1
    2
    2

现在我们应用accumarray

[c, r] = meshgrid(1:size(x, 2), iu);
y = accumarray([r(:), c(:)], x(:), [], @mean);

meshgrid[r(:), c(:)]的奇特技巧会产生一组索引:

[r(:), c(:)] =
     1     1
     2     1
     2     1
     1     2
     2     2
     2     2
     1     3
     2     3
     2     3

这些是输入值x(:)的索引,它是x的列向量等价物:

x(:) =
    27
    28
    28
    10
    20
    30
     8
    10
    50

积累过程:

  • 第一个值27进入单元< 1,1>。在输出矩阵中。
  • 第二值28进入单元格< 2,1>。在输出矩阵中。
  • 第三值28进入单元格< 2,1>在输出矩阵中。

看看刚刚发生了什么?两个值28都累积在同一个单元格中(最终它们将被平均)。这个过程继续:

  • 第四值10进入单元< 1,2>。在输出矩阵中。

依旧......

一旦所有值都存储在单元格中,函数mean就会应用于每个单元格,我们得到最终的输出矩阵:

y =
    27    10     8
    28    25    30

答案 1 :(得分:4)

您可以将accumarray应用于多个列as shown here

labels = x(:,1) - min(x(:, 1)) + 1; 
labels = [repmat(labels(:),size(x,2),1), kron(1:size(x,2),ones(1,numel(labels))).'];             
totals = accumarray(labels,x(:),[], @mean);

这是根据Gnovice's代码改编的。

要使代码适用于您的代码,您需要删除前面的所有零

totals(find(mean((totals == zeros(size(totals)))')), :) = [];

产生所需的

   26.0000   77.5700   17.9735   32.7200
   27.0000   40.5887   16.6100   31.5800
   28.0000   48.0609   22.8699   44.2100
   29.0000   95.3448   19.0000   37.7300
   30.0000   82.7273   30.4394   39.1400

答案 2 :(得分:0)

您可能会发现accumarray @mean有用:

假设第一列保留某些1 .. k的值k <= size(x,1),您可以使用

计算输出的每一列
col = accumarray( x(:,1), x(:,2), [], @mean ); % second column

答案 3 :(得分:0)

给你输入

x = [ ...
    26   77.5700   17.9735   32.7200; ...
    27   40.5887   16.6100   31.5800; ...
    28   60.4734   18.5397   33.6200; ...
    28   35.6484   27.2000   54.8000; ...
    29   95.3448   19.0000   37.7300; ...
    30   82.7273   30.4394   39.1400];

您可以使用unique的第三个输出创建一个索引数组,其中重复的vgalue共享相同的索引。

%Get index of unique values (1 - N)
[~, ~, ix] = unique(x(:,1))

然后您可以使用此数组重建矩阵,将重复值与您选择的功能相结合。

%Use accumarry to rebuild the matrix one column at a time
result = [...
    accumarray( ix, x(:,1), [], @max )  ...  %Many functions works here, as all inputs are the same.  E.G.  @mean, @max, @min
    accumarray( ix, x(:,2), [], @mean ) ...  %Use mean to combine data, per problem statement.
    accumarray( ix, x(:,3), [], @mean ) ...
    accumarray( ix, x(:,4), [], @mean ) ...
    ]