【问题标题】:MATLAB find and apply function to values of repeated indicesMATLAB 查找并将函数应用于重复索引的值
【发布时间】: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的对应位置,但是我从哪里开始呢?

【问题讨论】:

    标签: matlab matrix mean


    【解决方案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;我仍在学习它可以做什么。
    猜你喜欢
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    相关资源
    最近更新 更多