在MATLAB中,在一列中的一部分计算的平均,其中另一列满足条件(in matlab, calcul

2019-09-23 17:17发布

我是很新的MATLAB,和我很好奇如何做到这一点:

我有一个相当大的(27000x11)矩阵,以及第八列包含一个数,其有时会发生变化,但是常数像2000行(不一定是连续的)。

我想计算的,其中8列具有相同值的行第3列中的条目的平均值。 这对于第八列各值。 我也想绘制第3列的手段是8列的值的函数,但我可以做,如果我能得到一个包含一个新的矩阵(2×2)mean_of_3rd,8]。

例:(为了方便较小矩阵)

1 2 3 4 5
3 7 5 3 2
1 3 2 5 3
4 5 7 5 8
2 4 7 4 4

由于第四列具有在第1行和5相同的值,我想计算2和4(第2栏的对应元件,斜粗体)的平均,并与第4列的值把它放在另一个矩阵在一起。 因为第4列同样为3和5(粗体)具有用于这两个相同的值。

3 4
4 5

等等...这是可能的一个简单的方法?

Answer 1:

使用万能的,未充分利用的accumarray

此行给你的意思是由第2列积累的第四列的值:

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

这条线让你在每一组元素的数量:

count = accumarray( A(:,4) ,ones(size(A(:,4))))

现在,如果你想只筛选那些具有至少一个occurence:

>> filtered = means(count>1)

filtered =

     3
     4

这只会工作,在第4列正整数。


另一种可能性为在每个组元素的数量进行计数:

 count = accumarray( A(:,4) ,A(:,4),[],@numel)


Answer 2:

基于安德烈和罗迪的想法稍微改进的方法。 我们不能直接使用accumarray,因为数据是真实的,而不是整数。 但是 ,我们可以使用独特找到重复的条目索引 。 然后,我们操作上的整数。

% get unique entries in 4th column
[R, I, J] = unique(A(:,4));

% count the repeating entries: now we have integer indices!
counts = accumarray(J, 1, size(R));

% sum the 2nd column for all entries
sums   = accumarray(J, A(:,2), size(R));

% compute means
means  = sums./counts;

% choose only the entries that show more than once in 4th column
inds   = counts>1;
result = [means(inds) R(inds)];

以下合成数据时间比较:

A=randi(100, 1000000, 5);

% Rody's solution
Elapsed time is 0.448222 seconds.

% The above code
Elapsed time is 0.148304 seconds.


Answer 3:

我官方的回答:

A4 = A(:,4);
R = unique(A4);   

means = zeros(size(R));
inds  = false(size(R));

for jj = 1:numel(R)        
    I = A4==R(jj);
    sumI = sum(I);        
    inds(jj)  = sumI>1;
    means(jj) = sum(A(I,2))/sumI;        
end

result = [means(inds) R(inds)];

这是因为以下的原因。 这里的一切,我们已经拿出方案,在分析的形式:

%# sample data
A = [
    1 2 3 4 5
    3 7 5 3 2
    1 3 2 5 3
    4 5 7 5 8
    2 4 7 4 4];

%# accumarray
%# works only on positive integers in A(:,4)
tic
for ii = 1:1e4
    means = accumarray( A(:,4) ,A(:,2),[],@mean);
    count = accumarray( A(:,4) ,ones(size(A(:,4))));
    filtered = means(count>1);
end
toc

%# arrayfun
%# works only on integers in A(:,4)
tic
for ii = 1:1e4
    B = arrayfun(@(x) A(A(:,4)==x, 2), min(A(:,4)):max(A(:,4)), 'uniformoutput', false);
    filtered = cellfun(@mean, B(cellfun(@(x) numel(x)>1, B)) );    
end
toc


%# ordinary loop
%# works only on integers in A(:,4)    
tic
for ii = 1:1e4

    A4 = A(:,4);
    R = min(A4):max(A4);

    means = zeros(size(R));
    inds  = false(size(R));
    for jj = 1:numel(R)
        I = A4==R(jj);
        sumI = sum(I);        
        inds(jj) = sumI>1;
        means(jj) = sum(A(I,2))/sumI; 
    end

    filtered = means(inds);   
end
toc

结果:

Elapsed time is 1.238352 seconds.  %# (accumarray)
Elapsed time is 7.208585 seconds.  %# (arrayfun + cellfun)
Elapsed time is 0.225792 seconds.  %# (for loop)

普通环显然是去这里的路。

注意:如果没有mean的内循环。 这是因为, mean不是一个Matlab内置函数(至少,上R2010),以便使用它的循环内使循环不合格为JIT编译,这减缓下来由超过10倍使用上述形式的加速循环到的速度几乎5.5倍accumarray溶液。

看您的评论,几乎是微不足道的改变回路中的所有条目工作A(:,4)不仅仅是整数):

A4 = A(:,4);
R = unique(A4);   

means = zeros(size(R));
inds  = false(size(R));
for jj = 1:numel(A4)
    I = A4==R(jj);
    sumI = sum(I);        
    inds(jj) = sumI>1;
    means(jj) = sum(A(I,2))/sumI;
end

filtered = means(inds); 

我将复制并粘贴到顶部,我官方的回答:)



文章来源: in matlab, calculate mean in a part of one column where another column satisfies a condition