如何计算某个区域中稀疏矩阵的元素?

时间:2017-03-05 17:50:27

标签: matlab matrix sum vectorization sparse-matrix

我有一个稀疏矩阵,想要将区域划分为4个部分,将x和y分成2个等距的部分,并想要计算相应值的总和。

对于下面的示例,坐标x-y各自对应于[0,16],因此该区域是正方形。这个方块中有一个稀疏矩阵,它是对称的。我想将区域划分为较小的正方形并总结稀疏值。区域0:8,0:8有2个元素,它们的值都是(2,3)=(3,2)= 8所以总和是16.

第一个区域的总和应该是16,第二个和第三个区域是36,第四个区域是26

x = sparse(16,16);
x   (3,2)    =    8;
x  (10,2)    =    8;
x  (13,2)    =    8;
x  (14,2)    =    4;
x  (15,2)    =    4;
x   (2,3)    =    8;
x  (10,3)    =    4;
x  (13,3)    =    4;
x  (14,3)    =    2;
x  (15,3)    =    2;
x   (2,10)   =    8;
x   (3,10)   =    4;
x  (13,10)   =    4;
x  (14,10)   =    2;
x  (15,10)   =    2;
x   (2,13)   =    8;
x   (3,13)   =    4;
x  (10,13)   =    4;
x  (14,13)   =    2;
x  (15,13)   =    2;
x   (2,14)   =    4;
x   (3,14)   =    2;
x  (10,14)   =    2;
x  (13,14)   =    2;
x  (15,14)   =    1;
x   (2,15)   =    4;
x   (3,15)   =    2;
x  (10,15)   =    2;
x  (13,15)   =    2;
x  (14,15)   =    1;

我宁愿采用更短的方式,而不是为每个子广场写一条线。让我们说6000个子方块应该写6000行?

3 个答案:

答案 0 :(得分:1)

让我们以更方便的方式定义输入:

X = sparse([...
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 8, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 4, 4
      0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 2, 2
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      0, 8, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 2
      0, 4, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 1
      0, 4, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 1, 0]);

为方便起见,我们首先使阵列尺寸均匀。我们不会使用padarray(),因为这会使稀疏矩阵变满!

sz = size(X);
newX = sparse(sz(1)+1,sz(2)+1);

padTopLeft = true; % < chosen arbitrarily
if padTopLeft  
  newX(2:end,2:end) = X;
else % bottom right
  newX(1:sz(1),1:sz(2)) = X;   
end
%% Preallocate results:
sums = zeros(2,2,2);

方法#1:accumarray

我们创建了一个形式的掩码:

 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4

然后用它来汇总newX

的相应元素
sums(:,:,1) = reshape(...
                accumarray(reshape(repelem([1,2;3,4], ceil(sz(1)/2), ceil(sz(2)/2)),[],1),...
                           reshape(newX,                                            [],1),...
              [],@sum) ,2,2);

方法#2:blockproc(需要图像处理工具箱)

sums(:,:,2) = blockproc(full(newX), ceil(sz/2), @(x)sum(x.data(:)));

几点说明:

  1. 我也尝试了histcounts2,它很短,但它只告诉你每个象限中金额的值,而不是它们的总和:

    [r,c] = find(newX);
    histcounts2(r,c,[2,2])
    
  2. 我可能会使accumarray解决方案过于复杂。

答案 1 :(得分:0)

虽然你的问题不是很精确,而且你没有找到任何解决方案,但这就是你所要求的......

clear;clc;close;

Matrix=rand(20,20);
Acc=zeros(1,4);

Acc(1)=sum(sum( Matrix(1:size(Matrix,1)/2,1:size(Matrix,2)/2) ));
Acc(2)=sum(sum( Matrix((size(Matrix,1)/2)+1:end,1:size(Matrix,2)/2)));
Acc(3)=sum(sum( Matrix(1:size(Matrix,1)/2,((size(Matrix,2)/2)+1):end )));
Acc(4)=sum(sum( Matrix((size(Matrix,1)/2)+1:end,((size(Matrix,2)/2)+1):end)));

% Verification
sum(sum(Matrix)) % <- is the same with
sum(Acc)         % <- this

答案 2 :(得分:0)

您可以通过定义矩阵的4个角来定义矩阵内的任何矩形。然后使用for循环处理所有矩形。

regions = [
     1  8  1  8
     9 16  1  8
     1  8  9 16
     9 16  9 16
     ];

regionsum = zeros(size(regions,1),1);
for rr = 1:size(regions,1)
    submat = x(regions(rr,1):regions(rr,2),regions(rr,3):regions(rr,4));
    regionsum(rr) = sum(submat(:));
end

>> regionsum

regionsum =

    16
    36
    36
    26

如果您的意思是想要将方形矩阵划分为相同大小的2 ^ N(N> 2)个方格,则可以使用for循环编写regions

N = 1; % 2^N-by-2^N sub-squares
L = size(x,1);

dL = L/(2^N);
assert(dL==int32(dL),'Too many divisions')

segments = zeros(2^N,2);
for nn = 1:2^N
    segments(nn,:) = [1,dL]+dL*(nn-1);
end
regions = zeros(2^(2*N),4);
for ss = 1:2^N
    for tt = 1:2^N
        regions((2^N)*(ss-1) + tt,:) = [segments(ss,:),segments(tt,:)];
    end
end

示例输出,分为16个(N = 2)平方子矩阵:

>> regions

regions =

     1     4     1     4
     1     4     5     8
     1     4     9    12
     1     4    13    16
     5     8     1     4
     5     8     5     8
     5     8     9    12
     5     8    13    16
     9    12     1     4
     9    12     5     8
     9    12     9    12
     9    12    13    16
    13    16     1     4
    13    16     5     8
    13    16     9    12
    13    16    13    16

>> regionsum

regionsum =

    16
     0
    12
    24
     0
     0
     0
     0
    12
     0
     0
     8
    24
     0
     8
    10

>>