按嵌套的唯一值分组

时间:2017-02-02 21:43:09

标签: matlab for-loop matrix duplicates unique

我在Matlab中有一个矩阵A:

A = [176  5406  1  4  7903;
     155  5406  1  5  7903;
     122  5407  0  4  7903;
     140  5407  0  5  7904;
     130  5407  0  3  7904];

仅供参考 - 第二列是用户ID,第四列是时间。因此5406是一个用户,5407是另一个用户。这两个用户都有一些信息存储在我有兴趣访问的第一列和第四列中。

基本上我想做的是:

  1. 对于每个用户,在第一列中取其值的中位数。我编写的代码(如下)适用于此。

  2. 如果有两个相等的"时间"第5列中的值为每个用户,然后我想平均第4列中的值。因此,对于用户5406,时间值都是7903,我想要第4列中的值的平均值 - 即45的平均值最终得到一个值(4.5)。

  3. 但是例如对于下一个用户5407,我将有两个最终值 - 一个是5和3的平均值(因为7904重复),一个将是4(因为{{ 1}}不重复)。

    我对如何做到这一点感到有点困惑,我知道需要某种7903声明,但我已经被困在它上多年了。有人可以帮忙吗?

    由于

    第一部分的代码:

    if

2 个答案:

答案 0 :(得分:1)

您可以为每个用户的时间值(在循环内)运行unique并执行类似的子循环以收集该用户的唯一时间戳的平均值。

但在这里,我觉得使用accumarray比较整洁。在下面的第一个示例中,我稍微修改了您的代码。

% Get unique
[user, ~, userIdx] = unique(A(:,2));
nUser = numel(user);

% Allocate container for result
med = zeros(nUser,1);
men = cell(nUser,1); % <-- Need a cell since length of result could vary

for i = 1:nUser
    % Median of col #1
    med(i) = median(A(userIdx == i, 1));

    % Mean of col #4 for unique times
    [~, ~, timeIdx] = unique(A(userIdx == i, 5));
    men{i} = accumarray(timeIdx, A(userIdx == i, 4), [], @mean);
end

结果:

>> med =
        165.5
          130

>> celldisp(men)
men{1} =
          4.5
men{2} =
          4
          4

要进一步挤压它,您可以为整个A花费唯一的时间,并使用accumarray进行两者

[~, ~, userIdx] = unique(A(:,2));
[~, ~, timeIdx] = unique(A(:,5));

med = accumarray(userIdx, A(:,1), [], @median);
men = accumarray([userIdx timeIdx], A(:,4), [], @mean, NaN);

这使得men不是一个单元格而是一个矩阵。因此必须填充空格(这里我选择NaN,因为0可能是@mean的结果)。

men =
          4.5          NaN
            4            4

如果您希望它作为没有NaN的单元格,您可以循环遍历行并选择非NaN值,或者仅将men计算放在循环中,或者以任何其他方式放置...

如果您确定A的第4列不包含任何负数或零数(平均值不应该冒为0),您可以将men的结果收集为稀疏矩阵代替

men = accumarray([userIdx timeIdx], A(:,4), [], @mean, 0, true);
men =
   (1,1)             4.5
   (2,1)               4
   (2,2)               4

答案 1 :(得分:0)

我在不使用任何循环的情况下为您的任务提供了另一种解决方案:

中位值。

u=unique(A(:,2));
umedians = arrayfun( @(x) median (A( A(:,2)==x, 1)), u);

说明: 首先找到所有唯一身份用户然后使用arrayfun查找当前用户的所有数据,并为每个用户计算median

第4列的平均值。

这项任务有点困难。我们可以这样:

temp = arrayfun( @(x) unique(A ( A(:,2)==x,5 )), u, 'UniformOutput',false);
result = cellfun( @(y,z) arrayfun( @(x) mean( A( A(:,2) == u(z) & A(:,5) == x ,4) ), ... 
          y, 'UniformOutput',false), temp , num2cell( [1:size(u,1)]'), 'UniformOutput',false)

说明:首先让我们为每个用户找到所有唯一的时间。将其保存到单元格数组temp。现在我们需要每个单元格找到相同的时间并计算平均值。因此,我们可以使用cellfuntemp的每个单元格创建它,并使用arrayfun来计算mean

希望它有所帮助!