【问题标题】:Sum over blocks in a 2D matrix - MATLAB对二维矩阵中的块求和 - MATLAB
【发布时间】:2014-10-09 13:59:53
【问题描述】:

我正在研究 Matlab,想知道如何在大型矩阵中添加项。具体来说,我有一个4914x4914 矩阵并想创建一个189x189 矩阵,其中每个项等于每个26x26 子集中项的总和。

为了说明,假设我有如下神奇的4x4 矩阵:

[16 2  3  13;

 5  11 10 8;

 9  7  6  12;

 4  14 15 1]

我想创建一个2x2 矩阵,它等于原始魔法4x4 中每个2x2 矩阵的总和,即:

[(16+2+5+11)   (3+13+10+8);

(9+7+4+14)  (6+12+15+1)]

感谢您的任何建议! 谢谢 杰克

【问题讨论】:

  • 如果你有图像处理工具箱,你可以使用blockproc

标签: matlab matrix


【解决方案1】:

假设A 是输入4914x4914 矩阵,这可能是一种有效的(就运行时间而言)方法 -

sublen = 26; %// subset length
squeeze(sum(reshape(sum(reshape(A,sublen,[])),size(A,1)/sublen,sublen,[]),2))

对于一个通用的块大小,让我们有一个函数 -

function out = sum_blocks(A,block_nrows, block_ncols)
out = squeeze(sum(reshape(sum(reshape(A,block_nrows,[])),...
                    size(A,1)/block_nrows,block_ncols,[]),2));
return

示例运行 -

>> A = randi(9,4,6);
>> A
A =
     8     2     4     9     4     5
     3     3     8     3     6     8
     9     6     6     7     1     9
     4     5     5     7     1     2
>> sum_blocks(A,2,3)
ans =
    28    35
    35    27
>> sum(sum(A(1:2,1:3)))
ans =
    28
>> sum(sum(A(1:2,4:6)))
ans =
    35
>> sum(sum(A(3:4,1:3)))
ans =
    35
>> sum(sum(A(3:4,4:6)))
ans =
    27

如果你想避免squeeze -

sum(permute(reshape(sum(reshape(A,sublen,[])),size(A,1)/sublen,sublen,[]),[1 3 2]),3)

基准测试

希望您关心性能,这是此处发布的所有解决方案的基准测试结果。我使用的基准测试代码 -

num_runs = 100; %// Number of iterations to run benchmarks
A = rand(4914);
for k = 1:50000
    tic(); elapsed = toc(); %// Warm up tic/toc
end

disp('---------------------- With squeeze + reshape + sum')
tic
for iter = 1:num_runs
    sublen = 26; %// subset length
    out1 = squeeze(sum(reshape(sum(reshape(A,sublen,[])),...
                                   size(A,1)/sublen,sublen,[]),2));
end
time1 = toc;
disp(['Avg. elapsed time = ' num2str(time1/num_runs) ' sec(s)']), clear out1 sublen

disp('---------------------- With kron + matrix multiplication')
tic
for iter = 1:num_runs
    n = 189; k = 26;
    B = kron(speye(k), ones(1,n));
    result = B*A*B';
end
time2 = toc;
disp(['Avg. elapsed time = ' num2str(time2/num_runs) ' sec(s)']),clear result n k B

disp('---------------------- With accumarray')
tic
for iter = 1:num_runs
    s = 26; n = size(A,1)/s;
    subs = kron(reshape(1:(n^2), n, n),ones(s));
    out2 = reshape(accumarray(subs(:), A(:)), n, n);
end
time2 = toc;
disp(['Avg. elapsed time = ' num2str(time2/num_runs) ' sec(s)']),clear s n subs out2

我在系统上获得的基准测试结果 -

---------------------- With squeeze + reshape + sum
Avg. elapsed time = 0.050729 sec(s)
---------------------- With kron + matrix multiplication
Avg. elapsed time = 0.068293 sec(s)
---------------------- With accumarray
Avg. elapsed time = 0.64745 sec(s)

【讨论】:

    【解决方案2】:

    另一种方法是将整个矩阵重塑为 4D 矩阵,并对第一维和第三维上的元素求和:

    result = squeeze(sum(sum(reshape(A,26,189,26,189),1),3));
    

    【讨论】:

    • 重塑为 4 维......太棒了:)
    【解决方案3】:

    如果您没有图像处理工具箱,则可以使用accumarray

    s = 26;
    n = size(A,1)/s;
    subs = kron(reshape(1:(n^2), n, n),ones(s)); 
    reshape(accumarray(subs(:), A(:)), n, n) 
    

    如果您决定以某种方式聚合而不是简单的总和,则这是可重用的,例如中位数:

    reshape(accumarray(subs(:), A(:), [], @median), n, n) 
    

    【讨论】:

    • +1 我正要写类似的东西!但我想知道是否有 kron 的替代品,因为这个功能总是那么慢......
    【解决方案4】:

    你当然可以使用矩阵乘法:

    n = 26;
    k = 189;
    B = kron(speye(k), ones(1,n));
    result = B*A*B';
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-23
      相关资源
      最近更新 更多