【问题标题】:Is it possible to average across array of structure sub-fields in Matlab without looping?是否可以在不循环的情况下对 Matlab 中的结构子字段数组进行平均?
【发布时间】:2018-01-08 06:15:37
【问题描述】:

我有一个函数可以处理单个数据集,并将结果指标存储在数据集中,如下所示:

trial_data.output_metric_a.value_1 = 2;
...
trial_1 = trial_data;

此函数应用于许多不同的试验,并存储为数组结构:

% trial_1.output_metric_a.value_1 = 4
% trial_2.output_metric_a.value_1 = 2
trials = [trial_1 ; trial_2];

是否可以得到子字段值的平均值和标准差 不循环数据结构?

理想情况下:

mean_trials = mean(trials)
mean_trials.output_metric_a.value_1 == 3 % true

解决这个问题的一个可能的循环实现可能是(显然这还有很多不足之处):

output_metric_a_value_1 = [];
...

for i:length(trials)
    output_metric_a_value_1(end+1) = trials(i).output_metric_a.value_1; 
    ... % For each output metric and value
end

mean_trials.output_metric_a.value_1 = mean(output_metric_a_value_1);

【问题讨论】:

  • 为了让您的问题更清楚,能否请您添加代码,包括您想用不带循环的代码替换的循环?
  • 更新了一个可以工作的循环解决方案的例子,不幸的是这是站不住脚的,因为我有 256 个输出指标。
  • 更好的解决方案(自 R2013 左右以来)是使用table。它更有效,因为每个表列都是一个数组。对数据应用各种操作也更容易。

标签: arrays matlab struct


【解决方案1】:

您可以将主结构转换为单元格,然后对内容进行操作:

% your data base:
trial_1.output_metric_a.value_1 = 4
trial_2.output_metric_a.value_1 = 2
trials = [trial_1 ; trial_2];

% convert to cell:
Ctrials=struct2cell(trials);
Atrials=[Ctrials{:}];
meanTrials=mean([Atrials.value_1])
meanTrials=
     3

【讨论】:

    【解决方案2】:

    特殊解决方案(非嵌套结构>数组)

    如前所述,只针对一级结构字段(非嵌套)基本上可以选择单线:

    sarr_mean = cellfun(@(fn) mean([sarr.(fn)]), fieldnames(sarr))
    

    备注:在非嵌套的情况下,实际上不需要将结果数组分配回结构。如果需要,您可以类似于下面的完整解决方案进行操作。

    完整解决方案(嵌套结构 > 嵌套结构)

    但是,对于任意嵌套的数组,我建议使用如下函数:

    % f... function handle
    % s... nested struct array
    function sarr_res = nestedSarrFun(f, s)
        if isstruct(s)
            % get fieldnames:
            fns = fieldnames(s);
            % get content:
            con = cellfun(@(fn) nestedSarrFun(f, [s.(fn)]), ...
                          fns, 'UniformOutput', false);
            % create return struct
            fnsCon = reshape([fns(:), con(:)]', [1,2*numel(fns)]);
            sarr_res = struct(fnsCon{:});
        else
            sarr_res = f(s);
        end
    end
    

    使用示例

    定义示例结构数组并通过nestedSarrFun应用mean

    % define example struct array "sarr" with fields
    %   .foo.bar1
    %       .bar2
    %   .dings
    sarr = struct();
    sarr(1).foo.bar1 = 2;
    sarr(1).foo.bar2 = 7;
    sarr(1).dings   = 1;
    sarr(2).foo.bar1 = 5;
    sarr(2).foo.bar2 = 5;
    sarr(2).dings   = 2;
    
    % apply mean to all nested fields:
    sarr_mean = nestedSarrFun(@mean, sarr);
    

    示例结果:

    sarr_mean.foo.bar1 = 3.5
    sarr_mean.foo.bar2 = 6
    sarr_mean.dings = 1.5
    

    【讨论】:

    • 我的用例确实使用了多层嵌套结构,所以这是合适的解决方案。
    【解决方案3】:

    在 Matlab2017(我不确定旧版本)中,结构数组可以返回其结构字段的数组,如下所示:

    struct1.x = 1;
    struct2.x = 2;
    
    % array of 2 structs:
    struct_array = [struct1, struct2];
    
    % array of field x of each struct:
    [struct_array.x]
    

    返回

    ans =
    
         1     2
    

    在您的情况下,数据不在结构的字段中,而是在子字段output_metric_a 中。因此,您首先需要这样做两次:

    trial1.output_metric_a.value_1 = 1;
    trial2.output_metric_a.value_1 = 2;
    
    trials = [trial1, trial2];
    
    output_metric_a_array = [trials.output_metric_a];
    
    value_1_array = [output_metric_a_array.value_1];
    
    mean_of_value_1 = mean(value_1_array)
    

    返回

    mean_of_value_1 =
    
        1.5000
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      相关资源
      最近更新 更多