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);
说明
要处理的输入值实际上是accumarray
的second参数。
accumarray
的 first 参数是一个矩阵,每一行是(累积的)输出矩阵中的一组索引,它对应于给定向量中匹配行的一个值作为第二个参数。
将输出视为元胞数组。第二个参数是输入值,第一个参数中的每一行告诉输出矩阵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 查找并将函数应用于重复索引的值的主要内容,如果未能解决你的问题,请参考以下文章