【问题标题】:MATLAB: extract values from 3d matrix at given row and column indcies using sub2ind 3dMATLAB:使用 sub2ind 3d 从给定行和列索引处的 3d 矩阵中提取值
【发布时间】:2020-11-15 10:01:55
【问题描述】:

我有 3d 矩阵 A,其中包含我的数据。在由矩阵row_col_idx 所示的行和列索引定义的多个位置处,我想提取沿第三维的所有数据,如下所示:

A = cat(3,[1:3;4:6], [7:9;10:12],[13:15;16:18],[19:21;22:24])  %matrix(2,3,4) 
row_col_idx=[1 1;1 2; 2 3]; 

idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
out=nan(size(A,3),size(row_col_idx,1));
for k=1:size(A,3) 
    temp=A(:,:,k);
    out(k,:)=temp(idx);          
end
out

这段代码的输出如下:

A(:,:,1) =

     1     2     3
     4     5     6


A(:,:,2) =

     7     8     9
    10    11    12


A(:,:,3) =

    13    14    15
    16    17    18


A(:,:,4) =

    19    20    21
    22    23    24


out =

     1     2     6
     7     8    12
    13    14    18
    19    20    24

输出符合预期。然而,实际的A row_col_idx 非常庞大,因此这段代码的计算成本很高。是否可以验证此代码以避免循环和temp 矩阵?

【问题讨论】:

    标签: arrays matlab vectorization


    【解决方案1】:

    这可以使用linear indexingimplicit expansion 进行矢量化:

    out = A( row_col_idx(:,1) + ...
            (row_col_idx(:,2)-1)*size(A,1) + ...
            (0:size(A,1)*size(A,2):numel(A)-1) ).';
    

    上面构建了一个与输出一样大的索引矩阵。如果由于内存限制而无法接受,可以通过重塑 A 来避免:

    sz = size(A); % store size A
    A = reshape(A, [], sz(3)); % collapse first two dimensions
    out = A(row_col_idx(:,1) + (row_col_idx(:,2)-1)*sz(1),:).'; % linear indexing along
    % first two dims of A
    A = reshape(A, sz); % reshape back A, if needed
    

    【讨论】:

    • 我想知道制作该索引矩阵的成本是多少... :)
    • @CrisLuengo 好点。我添加了第二个版本,以避免使用重塑
    • 哦,这个不错!
    • 第二种方法似乎对我的实际情况最有效,大小为A(300,220,280) row_col_idx (33,2),并运行代码1e4次。请在下面查看我的其他评论。
    【解决方案2】:

    一种更有效的方法是使用row_col_idx 向量的条目从A 中选择元素。我已经比较了大矩阵的两种方法,你可以看到计算速度要快得多。 对于问题中给出的A,它给出了相同的输出

    A = rand([2,3,10000000]);
    row_col_idx=[1 1;1 2; 2 3];
    
    idx = sub2ind(size(A(:,:,1)), row_col_idx(:,1),row_col_idx(:,2));
    out=nan(size(A,3),size(row_col_idx,1));
    tic;
    for k=1:size(A,3)
        temp=A(:,:,k);
        out(k,:)=temp(idx);
    end
    time1 = toc;
    
    %% More efficient method:
    out2 = nan(size(A,3),size(row_col_idx,1));
    tic;
    for jj = 1:size(row_col_idx,1)
        out2(:,jj) = [A(row_col_idx(jj,1),row_col_idx(jj,2),:)];
    end
    time2 = toc;
    
    fprintf('Time calculation 1: %d\n',time1);
    fprintf('Time calculation 2: %d\n',time2);
    

    作为输出:

    Time calculation 1: 1.954714e+01
    Time calculation 2: 2.998120e-01
    

    【讨论】:

    • 这两种方法的相对时间可能取决于A的三个维度的相对大小,以及row_col_idx的长度。此外,两个数量级的时间差比我预期的要大得多。你用的是什么版本的 MATLAB?我希望不是八度音阶?
    • 使用矩阵A(300,220,280) 和矩阵row_col_idx (33,2) 的实际大小,我需要至少运行1e4 次。 % 时间计算 1:1.720272e+02(@ASE 方法),% 时间计算 2:1.508412e+00(@Nathan 方法),% 时间计算 3:1.050692e+00(@Luis Mendo 方法1),% 时间计算 4 : 6.370173e-01 (@Luis Mendo method1)。
    • 仅供参考,我使用的是 2019b 版
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多