Check if two 3D numpy arrays contain overlapping 2D arrays

前端 未结 1 679
情话喂你
情话喂你 2020-11-27 07:52

I have two very large numpy arrays, which are both 3D. I need to find an efficient way to check if they are overlapping, because turning them both into sets first takes too

相关标签:
1条回答
  • 2020-11-27 08:36

    We could leverage views using a helper function that I have used across few Q&As. To get the presence of subarrays, we could use np.isin on the views or use a more laborious one with np.searchsorted.

    Approach #1 : Using np.isin -

    # https://stackoverflow.com/a/45313353/ @Divakar
    def view1D(a, b): # a, b are arrays
        a = np.ascontiguousarray(a)
        b = np.ascontiguousarray(b)
        void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
        return a.view(void_dt).ravel(),  b.view(void_dt).ravel()
    
    def isin_nd(a,b):
        # a,b are the 3D input arrays to give us "isin-like" functionality across them
        A,B = view1D(a.reshape(a.shape[0],-1),b.reshape(b.shape[0],-1))
        return np.isin(A,B)
    

    Approach #2 : We could also leverage np.searchsorted upon the views -

    def isin_nd_searchsorted(a,b):
        # a,b are the 3D input arrays
        A,B = view1D(a.reshape(a.shape[0],-1),b.reshape(b.shape[0],-1))
        sidx = A.argsort()
        sorted_index = np.searchsorted(A,B,sorter=sidx)
        sorted_index[sorted_index==len(A)] = len(A)-1
        idx = sidx[sorted_index]
        return A[idx] == B
    

    So, these two solutions give us the mask of presence of each of the subarrays from a in b. Hence, to get our desired count, it would be - isin_nd(a,b).sum() or isin_nd_searchsorted(a,b).sum().

    Sample run -

    In [71]: # Setup with 3 common "subarrays"
        ...: np.random.seed(0)
        ...: a = np.random.randint(0,9,(10,4,5))
        ...: b = np.random.randint(0,9,(7,4,5))
        ...: 
        ...: b[1] = a[4]
        ...: b[3] = a[2]
        ...: b[6] = a[0]
    
    In [72]: isin_nd(a,b).sum()
    Out[72]: 3
    
    In [73]: isin_nd_searchsorted(a,b).sum()
    Out[73]: 3
    

    Timings on large arrays -

    In [74]: # Setup
        ...: np.random.seed(0)
        ...: a = np.random.randint(0,9,(100,100,100))
        ...: b = np.random.randint(0,9,(100,100,100))
        ...: idxa = np.random.choice(range(len(a)), len(a)//2, replace=False)
        ...: idxb = np.random.choice(range(len(b)), len(b)//2, replace=False)
        ...: a[idxa] = b[idxb]
    
    # Verify output
    In [82]: np.allclose(isin_nd(a,b),isin_nd_searchsorted(a,b))
    Out[82]: True
    
    In [75]: %timeit isin_nd(a,b).sum()
    10 loops, best of 3: 31.2 ms per loop
    
    In [76]: %timeit isin_nd_searchsorted(a,b).sum()
    100 loops, best of 3: 1.98 ms per loop
    
    0 讨论(0)
提交回复
热议问题