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

时间:2017-05-16 21:12:46

标签: matlab pivot-table average accumarray

我有一组数据,其中我以3组读数记录值(以便能够获得SEM的一般概念)。我将它们记录在一个如下所示的列表中,我试图将其折叠成每组3个点的平均值:

Original Table

我想基本上将每3行折叠成一行,其中为该集合提供平均数据值。实质上,它看起来如下:

Desired result

这是我知道基本上如何在Excel中做的事情(即使用数据透视表),但我不知道如何在MATLAB中做同样的事情。我已经尝试过使用accumarray但很难知道如何合并多个条件。我需要创建一个subs数组,其数字对应于每组唯一的3个数据点。通过蛮力,我可以创建一个数组,如:

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

使用一些循环并将其作为我的子数组,但由于它不依赖于数据本身,并且可能始终存在奇怪的打嗝(即每组超过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

4 个答案:

答案 0 :(得分:4)

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

[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

答案 1 :(得分:3)

我认为

  • 您希望根据前三列的唯一值进行平均(不是在三行组中,尽管这两个条件在您的示例中重合);
  • 订单由第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的第三个输出与'rows''sorted'选项。这将根据所需顺序基于数据的前三列创建subs分组向量。然后,将其传递给accumarray计算均值。

答案 2 :(得分:0)

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 :也适用于非数字值。

答案 3 :(得分:0)

您还应该尝试查看findgroupssplitapply参考页面。在这里使用它们的最简单方法可能是将数据放在表格中:

rdd.isEmpty