accumarray
使用两行索引来创建一个矩阵,其中元素位于有效索引对的位置,并具有由指定函数指定的值,例如:
A = [11:20];
B = flipud([11:20]);
C = 1:10;
datamatrix = accumarray([A B],C);
这种方式datamatrix
将是一个带有值的20x20
矩阵。但是,如果A
和B
的值非常大,则会产生一个基本上为空的矩阵,在远角处有一小批数据。为了避免这种情况,可以将accumarray
设置为issparse
:
sparsedatamatrix = accumarray([A B],C,[],@sum,[],true);
如果min(A)
和/或min(B)
非常大,这将节省大量内存。
然而,我的问题是我有一个Mx7
矩阵,M~1e8
,我希望根据前两列中的索引来收集第三列到第七列的方法。第三列的标准偏差也基于第三列:
result = accumarray([data(:,1) data(:,2)],data(:,3),[],@std);
我想将此保存回表格,结构为[X Y Z std R G B I]
,其中X
和Y
是索引,Z
是该像素的平均高度, R
,G
,B
和I
是每个像素的平均值(颜色和强度),std
是高度的标准偏差(即粗糙度) 。在这种情况下使用issparse
无济于事,因为我使用accumarray
转换repmat
生成的矩阵。
此代码的要点是从点云估算一块土地的高度,粗糙度,颜色和强度。我舍入了X和Y中的坐标以创建一个网格,现在需要每个网格单元的平均值,但输出为“表”(不是MATLAB数据类型,而是一个不是默认矩阵输出的2D数组)。 / p>
所以,总结一下问题:
accumarray
或类似函数是否有办法在没有中间(可能非常大)的矩阵的情况下输出此表?
以下代码:
Xmax = max(Originaldata(:,1));
Ymax = max(Originaldata(:,2));
X_avg_grid=(Edgelength:Edgelength:Xmax*Edgelength)+Xorig;
TestSet = zeros(Xmax*Ymax,9);
xx = [1:length(X_avg_grid)]'; %#ok<*NBRAK>
TestSet(:,1) = repmat(xx,Ymax,1);
ll = 0:Xmax:Xmax*Ymax;
for jj = 1:Ymax
TestSet(ll(jj)+1:ll(jj+1),2) = jj;
end
for ll = 1:7
if ll == 2
tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@std);
tempdat = reshape(tempdat,[],1);
TestSet(:,ll+2) = tempdat;
elseif ll == 7
tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],1);
tempdat = reshape(tempdat,[],1);
TestSet(:,ll+2) = tempdat;
elseif ll == 1
tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,3),[],@mean);
tempdat = reshape(tempdat,[],1);
TestSet(:,ll+2) = tempdat;
else
tempdat = accumarray([Originaldata(:,1) Originaldata(:,2)],Originaldata(:,ll+1),[],@mean);
tempdat = reshape(tempdat,[],1);
TestSet(:,ll+2) = tempdat;
end
end
TestSet = TestSet(~(TestSet(:,9)==0),:);
这里的第九列只是每个单元格的点数。
Originaldata =
19 36 2.20500360107422 31488 31488 31488 31611
20 37 2.26400360107422 33792 33792 34304 33924
20 37 2.20000360107422 33536 33536 34048 33667
19 36 2.20500360107422 34560 34560 34560 34695
20 36 2.23300360107422 32512 32512 33024 32639
21 38 2.22000360107422 31744 31488 33024 31611
21 37 2.20400360107422 32512 32768 33792 32896
21 37 2.24800360107422 29696 29440 30720 29555
21 38 2.34800360107422 32768 32768 32768 32639
21 37 2.23000360107422 33024 33024 33536 33153
因此,对同一X,Y(例如[19 36]
或[21 37]
)上的所有点进行平均(高度,RGB,按此顺序强度)和第三列中的值,标准差为也希望:
Result =
19 36 2.2050036 0.00 33024 33024 33024 33153
21 37 2.227336934 0.02212088 31744 31744 32682.66 31868
依此类推其他数据。
我将代码更新为我的最新版本。这大大减少了内存开销,因为该函数现在一个接一个地创建网格而不是一次创建网格。但是,代码并行运行,因此仍然会创建八个同时网格,因此仍然可以理解解决方案。
答案 0 :(得分:3)
使用线性索引和2D稀疏矩阵的解决方案草图
lind = Originaldata(:,1) + max( Originaldata(:,1) ) * ( Originaldata(:,2) - 1 );
daccum(7,:) = accumarray( lind, 1, [], @sum, [], true ); %// start with last one to pre-allocate all daccum
daccum(1,:) = accumarray( lind, Originaldata(:,3), [], @mean, [], true );
daccum(2,:) = accumarray( lind, Originaldata(:,3), [], @std, [], true );
daccum(3,:) = accumarray( lind, Originaldata(:,4), [], @mean, [], true );
daccum(4,:) = accumarray( lind, Originaldata(:,5), [], @mean, [], true );
daccum(5,:) = accumarray( lind, Originaldata(:,6), [], @mean, [], true );
daccum(6,:) = accumarray( lind, Originaldata(:,7), [], @mean, [], true );
现在你只能得到你需要的东西
inter = [Originaldata(:,1), Originaldata(:,2), full( daccum(:,lind) )' ];
答案 1 :(得分:2)
您可以先使用unique
和'rows'
选项查找唯一的X和Y坐标对的索引,然后在调用{{3}时使用这些索引作为下标输入(你必须为每一列单独调用它,因为accumarray
不处理矩阵输入):
[xyPairs, ~, index] = unique(Originaldata(:, 1:2), 'rows');
nPairs = max(index);
Result = [xyPairs ...
accumarray(index, Originaldata(:, 3), [nPairs 1], @mean) ...
accumarray(index, Originaldata(:, 3), [nPairs 1], @std) ...
accumarray(index, Originaldata(:, 4), [nPairs 1], @mean) ...
accumarray(index, Originaldata(:, 5), [nPairs 1], @mean) ...
accumarray(index, Originaldata(:, 6), [nPairs 1], @mean) ...
accumarray(index, Originaldata(:, 7), [nPairs 1], @mean) ...
accumarray(index, ones(size(index)), [nPairs 1], @sum)];
答案 2 :(得分:1)
您可以预处理数据。
您可以通过这种方式实现的一件事就是删除不需要的行(例如那些具有两次或更少次数的行),这样您就不必处理0
标准差:
%// Count occurences:
combined_coord = Originaldata(:,1)*1E6+Originaldata(:,2); %// "concatenating" the coords
[C,~,ic] = unique(combined_coord);
occurences = [C accumarray(ic,1)];
%// Find all points that have <=2 occurences:
coords_to_remove = occurences((occurences(:,2)<=2),1);
%// Find valid lines:
valid_lns = ~sum(bsxfun(@eq,combined_coord,coords_to_remove'),2); %'
%// Filter original data:
new_data = Originaldata(valid_lns,:);