1

我有以下数据:

A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9]
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8]
C = [4; 10; 6; 3; 1]

A =
    1     2
    3     2
    4     7
   10     2
    6     7
   10     9

B =
    1     2     3
    4     4     9
    1     8     0
    3     7     9
    3     6     8

C.' =
    4    10     6     3     1

对于 I 中的每个唯一值,A(:,2)我需要在 中获取相应的值,在A(:,1)中查找它们的值C,然后在 中获取相关行B并计算它们的平均值。结果应该是length(unique(A(:,2))x size(B,2)

此示例的预期结果:

  • 值“2”:第 2、4 和 5 行的平均值B 说明:对应于值“2”的索引 1、3 和 10A位于索引 2、4、5 in 处C

相应地:

  • 值“7”:第 1 行和第 3 行的平均值B
  • 值“9”:第 2 行的平均值B

我现在通过应用和迭代每个值,搜索正确的索引unique来计算它。A我的数据集很大,所以需要很长时间。我怎样才能避免循环?

4

3 回答 3

6

让我们一步一步地做你在问题中所说的:

  1. 对于 中的每个唯一值 A(:, 2)

    [U, ia, iu] = unique(A(:, 2));
    
  2. 取相应的值并在 中 A(:, 1) 查找它们的值 C

    [tf, loc] = ismember(A(:, 1), C);
    

    还建议确保以防万一,所有值实际上都在C

    assert(all(tf))
    
  3. 然后取相关行 B 并计算它们的平均值

    [X, Y] = meshgrid(1:size(B, 2), iu);
    result = accumarray([Y(:), X(:)], reshape(B(loc, :), 1, []), [], @mean);
    

希望这可以帮助!:)

例子

%// Sample input
A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9];
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8];
C = [4; 10; 6; 3; 1];

%// Compute means
[U, ia, iu] = unique(A(:, 2));
[tf, loc] = ismember(A(:, 1), C);
[X, Y] = meshgrid(1:size(B, 2), iu);
result = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], @mean);

结果是:

result = 
   3.3333   5.6667   8.6667
   1.0000   5.0000   1.5000
   4.0000   4.0000   9.0000
于 2013-09-02T08:57:58.167 回答
3

这是另一种没有arrayfunaccumarray使用良好的老式矩阵乘法的解决方案:

r = bsxfun(@eq, A(:,1), C')*(1:numel(C))'; 
[~,m,n] = unique(A(:,2));
f=histc(n, 1:numel(m));
result = diag(1./f)*bsxfun(@eq, 1:numel(m), n).'*B(r,:);

我对其他两种解决方案进行了基准测试,它似乎比两者都快。对于 1000 次重复:

  • 此方法需要 0.205650 秒。
  • Eitan T 的解耗时 0.546976 秒。
  • matlabit 的解决方案需要 1.619039 秒。

这是基准代码:

N = 1e3;

tic
for k=1:N,
    r = bsxfun(@eq, A(:,1), C')*(1:numel(C))'; % faster than [~,r] = ismember(A(:,1), C)
    [~,m,n] = unique(A(:,2));
    f=histc(n, 1:numel(m));
    result2 = diag(1./f)*bsxfun(@eq, 1:numel(m), n).'*B(r,:);
end
toc

tic
for k=1:N,
    [U, ia, iu] = unique(A(:, 2));
    [tf, loc] = ismember(A(:, 1), C);
    [X, Y] = meshgrid(1:size(B, 2), iu);
    result1 = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], @mean);
end
toc

tic
for k=1:N,
    D = [arrayfun(@(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
    data = [B(D(:,1),:), D(:,2)];
    st = grpstats(data(:,1:3),data(:,4:4),{'mean'});
end
toc
于 2013-09-02T20:17:13.497 回答
1

谢谢,我也想到了:

D = [arrayfun(@(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
data = [B(D(:,1),:), D(:,2)];
st = grpstats(data(:,1:3),data(:,4:4),{'mean'});
于 2013-09-02T09:08:00.283 回答