【问题标题】:What's the fastest way to unroll a matrix in MATLAB?在 MATLAB 中展开矩阵的最快方法是什么?
【发布时间】:2015-12-28 07:12:39
【问题描述】:

如何翻转矩阵:

[ 0.12 0.23 0.34 ;
  0.45 0.56 0.67 ;
  0.78 0.89 0.90 ] 

进入一个有一堆行的“坐标”矩阵?

[ 1 1 0.12 ;
  1 2 0.23 ;
  1 3 0.34 ;
  2 1 0.45 ;
  2 2 0.56 ;
  2 3 0.67 ;
  3 1 0.78 ;
  3 2 0.89 ;
  3 3 0.90 ]

(行的排列是无关紧要的,重要的是数据在这个结构中)

现在我正在使用 for 循环,但这需要很长时间。

【问题讨论】:

    标签: performance matlab optimization matrix


    【解决方案1】:

    这是一个使用ind2sub的选项:

    mat= [ 0.12 0.23 0.34 ;
      0.45 0.56 0.67 ;
      0.78 0.89 0.90 ] ;
    
    [I,J] = ind2sub(size(mat), 1:numel(mat));
    r=[I', J', mat(:)]
    
    r =
    
        1.0000    1.0000    0.1200
        2.0000    1.0000    0.4500
        3.0000    1.0000    0.7800
        1.0000    2.0000    0.2300
        2.0000    2.0000    0.5600
        3.0000    2.0000    0.8900
        1.0000    3.0000    0.3400
        2.0000    3.0000    0.6700
        3.0000    3.0000    0.9000
    

    请注意,与您的示例相比,索引是相反的。

    【讨论】:

    • 或者,为了整洁而放弃一组中间体,ind2sub(size(A), 1:numel(A))
    • 他说行的排列是无关紧要的,所以这应该一样好。这样的行仍然是相同的。 (顺便说一句,参考你的笔记)
    【解决方案2】:
    A = [ .12 .23 .34 ;
          .45 .56 .67 ;
          .78 .89 .90 ];
    
    [ii jj] = meshgrid(1:size(A,1),1:size(A,2));
    B = A.';
    R = [ii(:) jj(:) B(:)];
    

    如果您不介意不同的顺序(根据您的编辑),您可以更轻松地做到这一点:

    [ii jj] = ndgrid(1:size(A,1),1:size(A,2));
    R = [ii(:) jj(:) A(:)];
    

    【讨论】:

      【解决方案3】:

      除了使用meshgrid 生成行/列索引之外,您还可以使用find 的所有三个输出,如下所示:

      [II,JJ,AA]= find(A.'); %' note the transpose since you want to read across
      M = [JJ II AA]
      M =
                  1            1         0.12
                  1            2         0.23
                  1            3         0.34
                  2            1         0.45
                  2            2         0.56
                  2            3         0.67
                  3            1         0.78
                  3            2         0.89
                  3            3          0.9
      

      应用有限,因为零会丢失。讨厌但正确的解决方法(感谢 user664303):

      B = A.'; v = B == 0; %' transpose to read across, otherwise work directly with A
      [II, JJ, AA] = find(B + v);
      M = [JJ II AA-v(:)];
      

      不用说,我会推荐其他解决方案之一。 :) 特别是ndgrid 是获取行列索引最自然的解决方案。

      【讨论】:

      • 哦,但是零……嗯
      • 用零覆盖大小写的不太优雅的解决方案:加然后减min(A(:))+1
      • Bug 修复且不损失准确性:B = A.'; v = B == 0; [II, JJ, AA] = find(B + v); M = [JJ II AA-v(:)];
      • @user664303:感谢您的建议。甚至我都不会使用这种find 方法,但是嘿......它确实有效。
      【解决方案4】:

      我发现ndgrid 是最自然的解决方案,但这里有一个有趣的方法来手动完成kronrepmat 这两个奇怪的组合:

      M = [kron(1:size(A,2),ones(1,size(A,1))).' ...  %' row indexes
           repmat((1:size(A,1))',size(A,2),1) ...     %' col indexes
           reshape(A.',[],1)]                         %' matrix values, read across
      

      简单的阅读调整,这在 MATLAB 中很自然:

      M = [repmat((1:size(A,1))',size(A,2),1) ...     %' row indexes (still)
           kron(1:size(A,2),ones(1,size(A,1))).' ...  %' column indexes
           A(:)]                                      %  matrix values, read down
      

      (也因为我的第一个答案是淫秽的。)


      我还发现kron 是一个很好的工具,可以一次复制每个元素,而不是像repmat 那样一次复制整个数组。例如:

      >> 1:size(A,2)
      ans =
           1     2     3
      >> kron(1:size(A,2),ones(1,size(A,1)))
      ans =
           1     1     1     2     2     2     3     3     3
      

      更进一步,我们可以生成一个名为 repel 的新函数来复制数组的元素而不是整个数组:

      >> repel = @(x,m,n) kron(x,ones(m,n));
      >> repel(1:4,1,2)
      ans =
           1     1     2     2     3     3     4     4
      >> repel(1:3,2,2)
      ans =
           1     1     2     2     3     3
           1     1     2     2     3     3
      

      【讨论】:

        猜你喜欢
        • 2016-02-06
        • 2020-09-02
        • 1970-01-01
        • 1970-01-01
        • 2013-05-20
        • 2013-02-08
        • 2012-11-30
        相关资源
        最近更新 更多