如何根据多个条件累积(平均)数据

How to accumulate (average) data based on multiple criteria

我有一组数据,其中记录了 3 个读数组的值(以便能够获得 SEM 的总体概念)。我将它们记录在如下列表中,我试图将其分解为每组 3 点的平均值:

我基本上想将每 3 行折叠成一行,其中给出了该组的平均数据值。本质上,它看起来如下:

这是我在 Excel 中基本上知道如何做的事情(即使用 Pivot table),但我不确定如何在 MATLAB 中做同样的事情。我试过使用 accumarray 但不知道如何从本质上合并多个条件。我需要创建一个 subs 数组,其中它的编号对应于每组唯一的 3 个数据点。通过蛮力,我可以创建一个数组,例如:

subs = [1 1 1; 2 2 2; 3 3 3; 4 4 4; ...]'

使用一些循环并将其作为我的 subs 数组,但由于它与数据本身无关,并且整个过程中可能会出现奇怪的问题(即每组超过 3 个数据点,或丢失数据等) .).我知道必须有某种方法可以将这种 Pivot-table-esque 分组用于类似这样的事情,但需要一些帮助才能将其付诸实践。谢谢。

这里是文本形式的输入数据:

Subject  Flow   On/Off   Values
1        10     1        2.20
1        10     1        2.50
1        10     1        2.60
1        20     1        5.50
1        20     1        6.10
1        20     1        5.90
1        30     1        10.10
1        30     1        10.50
1        30     1        10.50
1        10     0        1.90
1        10     0        2.20
1        10     0        2.30
1        20     0        5.20
1        20     0        5.80
1        20     0        5.60
1        30     0        9.80
1        30     0        10.20
1        30     0        10.20
2        10     1        5.70
2        10     1        6.00
2        10     1        6.10
2        20     1        9.00
2        20     1        9.60
2        20     1        9.40
2        30     1        13.60
2        30     1        14.00
2        30     1        14.00
2        10     0        5.40
2        10     0        5.70
2        10     0        5.80
2        20     0        8.70
2        20     0        9.30
2        20     0        9.10
2        30     0        13.30
2        30     0        13.70
2        30     0        13.70

我认为

  • 您想根据前三列的唯一值进行平均(而不是基于三行的组,尽管这两个条件在您的示例中是一致的);
  • 顺序由第 1 列决定,然后是第 3 列,然后是第 2 列。

然后,将您的数据表示为 x

[~, ~, subs] = unique(x(:, [1 3 2]), 'rows', 'sorted');
result = accumarray(subs, x(:,end), [], @mean);

给予

result =
    2.1333
    5.5333
   10.0667
    2.4333
    5.8333
   10.3667
    5.6333
    9.0333
   13.5667
    5.9333
    9.3333
   13.8667

如您所见,我正在使用 unique with the 'rows' and 'sorted' options. This creates the subs grouping vector based on first three columns of your data in the desired order. Then, passing that to accumarray 的第三个输出计算均值。

您可以像这样使用 unique and accumarray 来维护数据行的顺序:

[newData, ~, subs] = unique(data(:, 1:3), 'rows', 'stable');
newData(:, 4) = accumarray(subs, data(:, 4), [], @mean);

newData =

    1.0000   10.0000    1.0000    2.4333
    1.0000   20.0000    1.0000    5.8333
    1.0000   30.0000    1.0000   10.3667
    1.0000   10.0000         0    2.1333
    1.0000   20.0000         0    5.5333
    1.0000   30.0000         0   10.0667
    2.0000   10.0000    1.0000    5.9333
    2.0000   20.0000    1.0000    9.3333
    2.0000   30.0000    1.0000   13.8667
    2.0000   10.0000         0    5.6333
    2.0000   20.0000         0    9.0333
    2.0000   30.0000         0   13.5667

accumarray 确实是要走的路。首先,您需要使用 unique :

为每组值分配一个索引
[unique_subjects, ~, ind_subjects] = unique(vect_subjects);
[unique_flows, ~, ind_flows] = unique(vect_flows);
[unique_on_off, ~, ind_on_off] = unique(vect_on_off);

所以基本上,您现在得到了 ind_subjectsind_flowsind_on_off,它们是 [1..2][1..3][1..2] 中的值。

现在,您可以计算 [3x2x2] 数组中的平均值(在您的示例中):

mean_values = accumarray([ind_flows, ind_on_off, ind_subjects], vect_values, [], @mean);
mean_values = mean_values(:);

Nota :顺序根据您的示例设置。

然后你就可以构建摘要了:

[ind1, ind2, ind3] = ndgrid(1:numel(unique_flows), 1:numel(unique_on_off), 1:numel(unique_subjects));
flows_summary = unique_flows(ind1(:));
on_off_summary = unique_on_off(ind2(:));
subjects_summary = unique_subjects(ind3(:));

Nota :也适用于非数值。

您还应该尝试查看 findgroups and splitapply 参考页。在这里使用它们的最简单方法可能是将数据放在 table:

 >> T = array2table(data, 'VariableNames', { 'Subject', 'Flow', 'On_Off', 'Values'});
 >> [gid,Tgrp] = findgroups(T(:,1:3));
 >> Tgrp.MeanValue = splitapply(@mean, T(:,4), gid)
 Tgrp =
   12×4 table
     Subject    Flow    On_Off    MeanValue
     _______    ____    ______    _________
     1          10      0         2.1333   
     1          10      1         2.4333   
     1          20      0         5.5333   
     1          20      1         5.8333   
     1          30      0         10.067   
     1          30      1         10.367   
     2          10      0         5.6333   
     2          10      1         5.9333   
     2          20      0         9.0333   
     2          20      1         9.3333   
     2          30      0         13.567   
     2          30      1         13.867