【问题标题】:find numpy array in other numpy array在其他 numpy 数组中查找 numpy 数组
【发布时间】:2018-12-13 16:54:47
【问题描述】:

我需要在一个更大的 numpy 数组中找到一个小的 numpy 数组。例如:

import numpy as np
a = np.array([1, 1])
b = np.array([2, 3, 3, 1, 1, 1, 8, 3, 1, 6, 0, 1, 1, 3, 4])

一个函数

find_numpy_array_in_other_numpy_array(a, b)

应该返回索引

[3, 4, 11]

表示完整的numpy数组a出现在完整的numpy数组b中的位置。

在处理非常大的b 数组时,有一种蛮力方法可以解决这个问题:

ok = []
for idx in range(b.size - a.size + 1):
    if np.all(a == b[idx : idx + a.size]):
        ok.append(idx)

我正在寻找一种更快的方法来查找数组b 中完整数组a 的所有索引。快速方法还应该允许其他比较功能,例如找出ab 之间的最坏情况差异:

diffs = []
for idx in range(b.size - a.size + 1):
    bi = b[idx : idx + a.size]
    diff = np.nanmax(np.abs(bi - a))
    diffs.append(diff)

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    通用解决方案设置

    对于一个通用的解决方案,我们可以创建2D滑动窗口数组,然后执行相关操作-

    from skimage.util.shape import view_as_windows
    
    b2D = view_as_windows(b,len(a))
    

    NumPy equivalent implementation.

    问题 #1

    然后,要解决匹配索引问题,很简单 -

    matching_indices = np.flatnonzero((b2D==a).all(axis=1))
    

    问题 #2

    为了解决第二个问题,它通过记住任何获取输出元素的 ufunc 归约操作都将使用该 ufunc 的 axis 参数在建议的解决方案中转换为沿第二轴的归约来轻松映射 -

    diffs = np.nanmax(np.abs(b2D-a),axis=1)
    

    【讨论】:

    • 用 scikit-image 实现太棒了! 5 分钟的代码执行步骤减少到 5 秒。
    【解决方案2】:

    以下代码在数组 b 中查找序列中第一个元素 (a) 的所有匹配项。然后它创建一个新数组,其中包含您可能的候选序列列,将它们与完整序列进行比较,并过滤初始索引

    seq, arr = a, b
    len_seq = len(seq)    
    ini_idx = (arr[:-len_seq+1]==seq[0]).nonzero()[0] # idx of possible sequence canditates   
    seq_candidates = arr[np.arange(1, len_seq)[:, None]+ini_idx] # columns with possible seq. candidates   
    mask = (seq_candidates==seq[1:,None]).all(axis=0)
    idx = ini_idx[mask]
    

    【讨论】:

      【解决方案3】:

      您可以考虑使用 Numba 编译该函数。你可以这样做:

      import numpy as np
      import numba as nb
      
      @nb.njit(parallel=True)
      def search_in_array(a, b):
          idx = np.empty(len(b) - len(a) + 1, dtype=np.bool_)
          for i in nb.prange(len(idx)):
              idx[i] = np.all(a == b[i:i + len(a)])
          return np.where(idx)[0]
      
      a = np.array([1, 1])
      b = np.array([2, 3, 3, 1, 1, 1, 8, 3, 1, 6, 0, 1, 1, 3, 4])
      print(search_in_array(a, b))
      # [ 3  4 11]
      

      快速基准测试:

      import numpy as np
      
      np.random.seed(100)
      a = np.random.randint(5, size=10)
      b = np.random.randint(5, size=10_000_000)
      
      # Non-compiled function
      %timeit search_in_array.py_func(a, b)
      # 22.8 s ± 242 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
      
      # Compiled function
      %timeit search_in_array(a, b)
      # 54.7 ms ± 1.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
      

      如您所见,您可以获得约 400 倍的加速,并且内存成本相对较低(布尔数组与大数组大小相同)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-23
        • 2014-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多