【问题标题】:Find a vector placed horizontally or vertically in a matrix在矩阵中找到水平或垂直放置的向量
【发布时间】:2017-11-25 16:52:39
【问题描述】:

我试图在A 的大矩阵中找到一个向量B
B 可以是A 的多行一列,也可以是@987654325 的多列一行@。

例如:

A = [56  55  53  52  53;
     49  45  44  45  47;
     33  30  31  34  35;
     34  34  27  24  26;
     44  48  45  35  24;
     56  57  57  53  39;
     62  62  62  60  55;
     62  61  61  54  47;
     49  47  42  40  32;
     47  42  44  45  40];

B = [34 27 24];

我需要一个返回行和列索引的函数,例如:
find(A, B) → 第 4 行,第 2 到第 4 列(对于给定的示例)。

如何做到这一点?

【问题讨论】:

    标签: matlab matrix vector match


    【解决方案1】:

    我们可以将矩阵typecastchar 并使用strfind 搜索矩阵:

    %Horizontal search
    A_str_h = typecast(A.','char');
    B_str = typecast(B,'char');
    charsize = numel(B_str)/numel(B);
    pos_h = strfind(A_str_h,B_str)-1;
    pos_h = pos_h(mod(pos_h,charsize)==0)/charsize+1;
    [col_h row_h] = ind2sub(flip(size(A)),pos_h);
    idx_h = col_h <= (size(A,2)-numel(B)+1);
    row_h = row_h(idx_h);
    col_h = col_h(idx_h);
    
    %Vertical search
    A_str_v = typecast(A,'char');
    B_str = typecast(B,'char');
    charsize = numel(B_str)/numel(B);
    pos_v = strfind(A_str_v,B_str)-1;
    pos_v = pos_v(mod(pos_v,charsize)==0)/charsize+1;
    [row_v col_v] = ind2sub(size(A),pos_v);
    idx_v = row_v <= (size(A,1)-numel(B)+1);
    row_v = row_v(idx_v);
    col_v = col_v(idx_v);
    

    使用convn的另一种解决方案:

    n = numel(B);
    C = A == reshape(B,1,1,n);
    mask_h = permute(eye(n),[3 2 1]);
    mask_v = permute(eye(n),[1 3 2]);
    [xh yh]=find(convn(C,mask_h,'valid')==n);
    [xv yv]=find(convn(C,mask_v,'valid')==n);
    

    [xh yh]代表横向匹配的起始位置,[xv yv]代表纵向匹配的起始位置。

    这是测试不同方法的结果,将A 设置为[2750 * 1250] 矩阵和B 的不同大小:

    结果表明CONVN 的效率低于其他方法,不适用于大尺寸的数组,而STRFIND 适用于所有尺寸的数组。

    *方法在 Octave 中测试。

    【讨论】:

      【解决方案2】:

      rahnema1 和 m7913d 之间的基准测试

      水平和垂直匹配

      使用timeit 为给定示例(小A)和100^2 更大的示例(大A)对rahnema1 和m7913d 的解决方案进行基准测试,给出结果如下:

      Method   | Small A    | Large A
      --------------------------------
      rahnema1 | 4.0416e-05 | 0.0187
      m7913d   | 2.5242e-05 | 0.0129
      

      请注意,m7913d 的解决方案要快约 50%。

      仅水平(或垂直)匹配

      如果只对横向匹配感兴趣,会得到以下结果:

      Method   | Small A    | Large A
      --------------------------------
      rahnema1 | 9.6752e-06 | 0.0115
      m7913d   | 5.8634e-06 | 0.0056
      

      在这种情况下,m7913d 的解决方案更加有利,速度提高了约 100%。

      完整的基准代码

      A=[56  55  53  52  53;
        49  45  44  45  47;
        33  30  31  34  35;
        34  34  27  24  26;
        44  48  45  35  24;
        56  57  57  53  39;
        62  62  62  60  55;
        62  61  61  54  47;
        49  47  42  40  32;
        47  42  44  45  40];
      B=[34 27 24];
      A_large = repmat(A, 100, 100);
      
      t_m7913d = timeit(@() m7913d(A, B))
      t_rahnema = timeit(@() rahnema1(A, B))
      
      t_large_m7913d = timeit(@() m7913d(A_large, B))
      t_large_rahnema = timeit(@() rahnema1(A_large, B))
      
       function [row_h, col_h, row_v, col_v] = m7913d(A, B)
          Ah = true(size(A) - [0 length(B)-1]);
          Av = true(size(A) - [length(B)-1 0]);
          for i=1:length(B)
              Ah= Ah & A(:, i:end-3+i) == B(i);
              Av= Av & A(i:end-3+i, :) == B(i);
          end
          [row_h, col_h] = find(Ah);
          [row_v, col_v] = find(Av);
      end
      
      function [row_h, col_h, row_v, col_v] = rahnema1(A, B) 
          n = numel(B);
          C = A == reshape(B,1,1,n);
          mask_h = permute(eye(n),[3 2 1]);
          mask_v = permute(eye(n),[1 3 2]);
          [row_h, col_h]=find(convn(C,mask_h,'valid')==n);
          [row_v, col_v]=find(convn(C,mask_v,'valid')==n);
      end
      

      【讨论】:

        【解决方案3】:

        对于B的固定大小,可以使用如下方法:

        [row, col] = find(A(:, 1:end-2) == B(1) & ...
                          A(:, 2:end-1) == B(2) & ...
                          A(:, 3:end) == B(3))
        

        这将返回row = 4col = 2,即B(1)A 中的位置。

        更多信息请参见Find Array Elements That Meet a Condition

        这可以使用 for 循环扩展到可变大小向量B

        Ah = true(size(A) - [0 length(B)-1]);
        for i=1:length(B)
            Ah= Ah & A(:, i:end-length(B)+i) == B(i);
        end
        [row, col] = find(Ah);
        

        这可以很容易地扩展到找到B 水平和垂直的出现,如下所示:

        Ah = true(size(A) - [0 length(B)-1]);
        Av = true(size(A) - [length(B)-1 0]);
        for i=1:length(B)
            Ah= Ah & A(:, i:end-3+i) == B(i);
            Av= Av & A(i:end-3+i, :) == B(i);
        end
        [row_h, col_h] = find(Ah);
        [row_v, col_v] = find(Av);
        

        基准测试

        请注意,尽管如此,我使用的是 for 循环,但这种方法比 rahnema1 的解决方案要快,尤其是如果您只对水平(或垂直)匹配感兴趣。请查看the benchmark 了解更多信息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-11
          • 2010-10-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多