2

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

例如,

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

4 回答 4

6

一种更通用的方法将unique用于查找唯一索引值:

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

然后accumarray

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

解释

要处理的输入值实际上是 的第二个参数accumarray

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

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

例子

这是一个带有较小矩阵的简短示例:

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

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

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

VectorU存储唯一值,并iu指示与每一行关联的值的索引(请注意,在此解决方案中,我们没有使用 for 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
于 2013-04-18T15:40:28.233 回答
4

您可以应用accumarray到多个列,如此处所示

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 的代码。

为了让它适用于您的代码,您需要删除前面的所有零

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
于 2013-04-18T15:37:41.817 回答
0

您可能会发现accumarray有用@mean

假设第一列包含1 .. ksome的值k <= size(x,1),您可以使用计算输出的每一列

col = accumarray( x(:,1), x(:,2), [], @mean ); % second column
于 2013-04-18T15:31:43.513 回答
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.

%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 ) ...
    ]
于 2013-04-18T15:37:27.337 回答