2

我有一个按第 1 列排序的 21128x9 单元格数组,例如(大量简化):

    A=[1 3; 1 5; 1 3; 2 1; 2 2; 2 3; 3 5; 3 5]

    A =

         1     3
         1     5
         1     3
         2     1
         2     2
         2     3
         3     5
         3     5

其中第 1 列中的某些值比其他值重复更多。

我想要做的是为第一列的每个值获取第二列的平均值,但仅针对前两个值。

IE

    ans= 1 4
         2 1.5
         3 5

我正在尝试使用这个基本功能

    means = accumarray(A(:,1) ,A(:,2),[],@mean);

但我不知道如何让它只适用于每组的前两个值。我假设我需要一个for循环,类似于:

    for ;
        means = accumarray(A(:,1) ,A(:,2),[],@mean);
    end

我不知道for需要什么。

4

1 回答 1

4

accumarray将向量传递给匿名函数,因此您可以这样做,例如:

A = [1 3; 1 5; 1 3; 2 1; 2 2; 2 3; 3 5; 3 5];
maxAvgs = 3;
accumarray(A(:, 1), A(:, 2), [], @(x)mean(x(1:min(length(x), maxAvgs))))

ans =

3.6667
2.0000
5.0000

maxAvgs = 2;
accumarray(A(:, 1), A(:, 2), [], @(x)mean(x(1:min(length(x), maxAvgs))))

ans =

4.0000
1.5000
5.0000

每当您在涉及匿名函数的情况下不确定时,您可以将匿名函数编写为@(varargin)disp(varargin); 这将显示输入参数。在这种情况下,这不起作用,因为accumarray 要求您传递给它的函数返回一个参数。但是,您仍然可以将其设置为匿名函数并从脚本运行您的代码;在编辑器窗口的行上设置断点,确保为断点的位置选择“匿名函数”。

编辑:

在我的实际数据中,有些有 60 个值,有些有 120,有些有 180。此外,是否可以对下一批值(即值 61-120,然后 121-180)运行均值函数?

要按照您在评论中提出的要求,我建议创建一个函数splitMean并将其传递给accumarray

function y = splitMean(x, n)
% If length of x doesn't divide by n, the extra elements will be averaged
% separately
extra = mod(length(x), n);
M = length(x)-extra;

meanData = reshape(x(1:M), M / n, n);

extraMean = [];
if extra > 0, extraMean = mean(x(M+1:end)); end
if ~isempty(meanData)
    y = {[mean(meanData).'; extraMean]};
else
    y = {extraMean};
end

然后,

maxAvgs = 2;
cell2mat(accumarray(A(:, 1), A(:, 2), [], @(x)splitMean(x, maxAvgs)))

ans =

4.0000
3.0000
1.5000
3.0000
5.0000

%%% Without the cell2mat:

ans =

[2x1 double]
[2x1 double]
[         5]

这样,您就可以获得每个组可以同时提供的所有方法。注意cell2mat. 如果您希望它们按组索引拆分,则将其删除,您将获得一个元胞数组。

于 2013-04-12T11:34:25.513 回答