6

accumarray使用两行索引创建一个矩阵,其元素位于有效索引对的位置,其值由指定函数分配,例如:

A = [11:20]; 
B = flipud([11:20]); 
C = 1:10;
datamatrix = accumarray([A B],C);

这种方式datamatrix将是一个20x20带有值的矩阵。A然而,如果和的值B非常大,这将导致一个大部分为空的矩阵,在远角有一小批数据。为了规避这一点,可以设置accumarrayissparse

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],其中XY是索引,Z是该像素的平均高度,RGBI每个像素的平均值(颜色和强度),std是高度的标准偏差(即粗糙度)。在这种情况下使用issparse没有帮助,因为我转换了accumarray使用repmat.

这段代码的重点是从点云估计一块土地的高度、粗糙度、颜色和强度。我将 X 和 Y 中的坐标四舍五入以创建一个网格,现在需要每个网格单元格的平均值,但输出为“表格”(不是 MATLAB 数据类型,而是一个不是默认矩阵输出的二维数组)。

所以,用这个问题来结束:

有没有一种方法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

其余数据以此类推。

我将我的代码更新到我拥有的最新版本。这大大减少了内存开销,因为该函数现在一个接一个地创建网格,而不是一次创建所有网格。但是,代码是并行运行的,因此仍然会同时创建八个网格,因此仍然需要一个解决方案。

4

3 回答 3

3

使用线性索引和二维稀疏矩阵的解决方案草图

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) )' ];
于 2015-08-24T14:37:15.980 回答
2

您可以首先使用unique'rows'选项来查找唯一 X 和 Y 坐标对的索引,然后在调用时将这些索引用作下标输入accumarray(您必须为每一列单独调用它,因为accumarray没有t 处理矩阵输入):

[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)];
于 2017-04-20T16:30:39.320 回答
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,:);
于 2015-10-31T15:52:12.497 回答