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

Posted

技术标签:

【中文标题】MATLAB 查找并将函数应用于重复索引的值【英文标题】:MATLAB find and apply function to values of repeated indices 【发布时间】:2013-04-11 19:11:05 【问题描述】:

我有一个 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的对应位置,但是我从哪里开始呢?

【问题讨论】:

【参考方案1】:

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

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

然后accumarray:

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

说明

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

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

将输出视为元胞数组。第二个参数是输入值,第一个参数中的每一行告诉输出矩阵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 进入输出矩阵中的单元格 。 第二个值 28 进入输出矩阵中的单元格 。 第三个值 28 进入输出矩阵中的单元格 。

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

第四个值 10 进入输出矩阵中的单元格 。

等等……

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

y =
    27    10     8
    28    25    30

【讨论】:

@8eastFromThe3ast 我已经为你添加了解释。 @8eastFromThe3ast 这是更可靠的解决方案 @Eitan T Gosh 很详细!非常感谢。目前,Dan 的 kludge 效果很好,但是当我有更多时间时,我会按照你的建议进行工作,看看哪个效果更好!再次感谢 @8eastFromThe3ast 没问题。目的是学习,我们都在这里互相帮助。 Dan 和 Eitan 的解决方案基本相同,唯一的区别在于 subs(标签)矩阵的创建方式。在我看来,Eitan 的解决方案更干净,我个人更喜欢 meshgrid,甚至是几次调用 repmat。过去,Kron 速度较慢。【参考方案2】:

您可以将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

【讨论】:

看来你又做了一次,那只是票!非常感谢,我整天都在用头撞墙试图弄清楚。 虽然这个解决方案并不健壮(主要是因为我不了解它的工作原理) - 最后修复以摆脱零并不是一个好兆头。就像我不确定如果第一列中有否定会发生什么......它仍然需要工作,但我认为它现在可以工作。 labels = x(:,1); 这行需要改进,除非 x(:,1) 只包含一直在增加的正整数。 sortrows 可以轻松解决始终增加的问题,labels = x(:,1) - min(x(:, 1)) + 1 可以轻松解决积极问题,我认为这也解决了零填充问题 是的,第一列是参与者编号的索引,所以没有负值!它现在完美地完成了这项工作,所以我会继续使用它。 我想我现在已经修好了,我改变了代码的第一行和最后一行【参考方案3】:

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

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

col = accumarray( x(:,1), x(:,2), [], @mean ); % second column

【讨论】:

我尝试过使用accumarray,但是因为我想将函数同时应用于多个列,所以我的VAL 值与函数不兼容。 @8eastFromThe3ast 但您现在可以遍历列【参考方案4】:

根据您的输入

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 ) ...
    ]

【讨论】:

+1 用于使用 accumarray,-1 用于一次构建一个列 :) 如果您构建 @987654327,您可以accumarray 一次构建所有列@正确... :) 指出。我从不每天使用accumaray;我仍在学习它可以做什么。

以上是关于MATLAB 查找并将函数应用于重复索引的值的主要内容,如果未能解决你的问题,请参考以下文章

将函数应用于两列并将输出映射到新列[重复]

在 R 中查找具有最小峰宽的峰 - 类似于 MATLAB 函数

编写在数字数组中查找元素索引的函数[重复]

setdefault函数的用法及个人理解

setdefault函数的用法及个人理解

MATLAB:无法调用或索引到临时数组[重复]