我对matlab很新,我很好奇如何做到这一点:
我有一个相当大的(27000x11)矩阵,第8列包含一个有时会改变的数字,但对于2000行(不一定是连续的)是恒定的。
我想计算第7列中第8列具有相同值的行的平均值。这是第8列的每个值。 我还想将第3列的平均值绘制为第8列值的函数,但如果我能得到包含[mean_of_3rd,8th]的新矩阵(2x2),我可以这样做。
Ex :(为方便起见,矩阵较小)
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
由于第4列在第1行和第5行中具有相同的值,我想计算2和4的平均值(第2列的相应元素,斜体粗体)并将其与第4列一起放入另一个矩阵中值。 3和5(粗体)相同,因为第4列具有相同的值。
3 4
4 5
依此类推......这是否可以轻松实现?
答案 0 :(得分:4)
使用全能,未充分利用的accumarray
:
此行显示第2列累计的第4列的平均值:
means = accumarray( A(:,4) ,A(:,2),[],@mean)
此行显示每组中的元素数:
count = accumarray( A(:,4) ,ones(size(A(:,4))))
现在,如果您只想过滤那些至少有一次出现的那些:
>> filtered = means(count>1)
filtered =
3
4
这仅适用于第4列中的正整数。
计算每组元素数量的另一种可能性:
count = accumarray( A(:,4) ,A(:,4),[],@numel)
答案 1 :(得分:2)
基于Andrey和Rody的想法的略微改进的方法。我们不能直接使用accumarray,因为数据是真实的,而不是整数。 但,我们可以使用unique来查找重复条目的索引。然后我们对整数进行操作。
% 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.
答案 2 :(得分:1)
我的正式答复:
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倍以上。使用上面的形式将循环加速到几乎是accumarray
解决方案速度的5.5倍。
判断你的评论,改变循环以处理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);
我会将其复制粘贴到顶部作为我的正式答案:)