For short arrays, using sets is probably the clearest and most readable way to do it.

Another way is to use numpy.intersect1d. You'll have to trick it into treating the rows as a single value, though... This makes things a bit less readable...

import numpy as np

A = np.array([[1,4],[2,5],[3,6]])
B = np.array([[1,4],[3,6],[7,8]])

nrows, ncols = A.shape
dtype={'names':['f{}'.format(i) for i in range(ncols)],
       'formats':ncols * [A.dtype]}

C = np.intersect1d(A.view(dtype), B.view(dtype))

# This last bit is optional if you're okay with "C" being a structured array...
C = C.view(A.dtype).reshape(-1, ncols)

For large arrays, this should be considerably faster than using sets.

Answer from Joe Kington on Stack Overflow
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.intersect1d.html
numpy.intersect1d — NumPy v2.5 Manual
If True, the indices which correspond to the intersection of the two arrays are returned. The first instance of a value is used if there are multiple.
Top answer
1 of 6
4

This should do it:

In [11]:

def f(arrA, arrB):
    return not set(map(tuple, arrA)).isdisjoint(map(tuple, arrB))
In [12]:

f(A, B)
Out[12]:
True
In [13]:

f(A, C)
Out[13]:
False
In [14]:

f(B, C)
Out[14]:
False

To find intersection? OK, set sounds like a logical choice. But numpy.array or list are not hashable? OK, convert them to tuple. That is the idea.

A numpy way of doing involves very unreadable boardcasting:

In [34]:

(A[...,np.newaxis]==B[...,np.newaxis].T).all(1)
Out[34]:
array([[False, False],
       [ True, False],
       [False, False]], dtype=bool)
In [36]:

(A[...,np.newaxis]==B[...,np.newaxis].T).all(1).any()
Out[36]:
True

Some timeit result:

In [38]:
#Dan's method
%timeit set_comp(A,B)
10000 loops, best of 3: 34.1 µs per loop
In [39]:
#Avoiding lambda will speed things up
%timeit f(A,B)
10000 loops, best of 3: 23.8 µs per loop
In [40]:
#numpy way probably will be slow, unless the size of the array is very big (my guess)
%timeit (A[...,np.newaxis]==B[...,np.newaxis].T).all(1).any()
10000 loops, best of 3: 49.8 µs per loop

Also the numpy method will be RAM hungry, as A[...,np.newaxis]==B[...,np.newaxis].T step creates a 3D array.

2 of 6
3

Using the same idea outlined here, you could do the following:

def make_1d_view(a):
    a = np.ascontiguousarray(a)
    dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(dt).ravel()

def f(a, b):
    return len(np.intersect1d(make_1d_view(A), make_1d_view(b))) != 0

>>> f(A, B)
True
>>> f(A, C)
False

This doesn't work for floating point types (it will not consider +0.0 and -0.0 the same value), and np.intersect1d uses sorting, so it is has linearithmic, not linear, performance. You may be able to squeeze some performance by replicating the source of np.intersect1d in your code, and instead of checking the length of the return array, calling np.any on the boolean indexing array.

🌐
The Web Dev
thewebdev.info › home › how to get intersecting rows across two 2d python numpy arrays?
How to get intersecting rows across two 2D Python NumPy arrays? - The Web Dev
November 1, 2021 - To get intersecting rows across two 2D Python NumPy arrays, we can convert the arrays to sets and then use the & operator to get the intersection of both sets.
Find elsewhere
🌐
Educative
educative.io › answers › what-is-the-numpyintersect1d-function-in-python
What is the numpy.intersect1d() function in Python?
Line 1: We import numpy as np. Lines 3–4: We create two input arrays, a and b. Line 7: We use intersect1d() to find the intersection of a and b, and print the results. Lines 10–11: We create two input arrays, c and d. These are two 2D arrays.
🌐
Data Science Parichay
datascienceparichay.com › home › blog › python – get intersection of two numpy arrays
Python - Get Intersection of Two Numpy Arrays - Data Science Parichay
June 17, 2022 - # create two 2d arrays ar1 = ... elements between both the input arrays as the return value. For more on the numpy intersect1d() function, refer to its documentation....
Top answer
1 of 4
17

You can use a view of the array as a single dimension to the intersect1d function like this:

def multidim_intersect(arr1, arr2):
    arr1_view = arr1.view([('',arr1.dtype)]*arr1.shape[1])
    arr2_view = arr2.view([('',arr2.dtype)]*arr2.shape[1])
    intersected = numpy.intersect1d(arr1_view, arr2_view)
    return intersected.view(arr1.dtype).reshape(-1, arr1.shape[1])

This creates a view of each array, changing each row to a tuple of values. It then performs the intersection, and changes the result back to the original format. Here's an example of using it:

test_arr1 = numpy.array([[0, 2],
                         [1, 3],
                         [4, 5],
                         [0, 2]])

test_arr2 = numpy.array([[1, 2],
                         [0, 2],
                         [3, 1],
                         [1, 3]])

print multidim_intersect(test_arr1, test_arr2)

This prints:

[[0 2]
 [1 3]]
2 of 4
5

you can use http://pypi.python.org/pypi/Polygon/2.0.4, here is an example:

>>> import Polygon
>>> a = Polygon.Polygon([(0,0),(1,0),(0,1)])
>>> b = Polygon.Polygon([(0.3,0.3), (0.3, 0.6), (0.6, 0.3)])
>>> a & b
Polygon:
  <0:Contour: [0:0.60, 0.30] [1:0.30, 0.30] [2:0.30, 0.60]>

To convert the result of cv2.findContours to Polygon point format, you can:

points1 = contours[0].reshape(-1,2)

This will convert the shape from (N, 1, 2) to (N, 2)

Following is a full example:

import Polygon
import cv2
import numpy as np
from scipy.misc import bytescale

y, x = np.ogrid[-2:2:100j, -2:2:100j]

f1 = bytescale(np.exp(-x**2 - y**2), low=0, high=255)
f2 = bytescale(np.exp(-(x+1)**2 - y**2), low=0, high=255)


c1, hierarchy = cv2.findContours((f1>120).astype(np.uint8), 
                                       cv2.cv.CV_RETR_EXTERNAL, 
                                       cv2.CHAIN_APPROX_SIMPLE)

c2, hierarchy = cv2.findContours((f2>120).astype(np.uint8), 
                                       cv2.cv.CV_RETR_EXTERNAL, 
                                       cv2.CHAIN_APPROX_SIMPLE)


points1 = c1[0].reshape(-1,2) # convert shape (n, 1, 2) to (n, 2)
points2 = c2[0].reshape(-1,2)

import pylab as pl
poly1 = pl.Polygon(points1, color="blue", alpha=0.5)
poly2 = pl.Polygon(points2, color="red", alpha=0.5)
pl.figure(figsize=(8,3))
ax = pl.subplot(121)
ax.add_artist(poly1)
ax.add_artist(poly2)
pl.xlim(0, 100)
pl.ylim(0, 100)

a = Polygon.Polygon(points1)
b = Polygon.Polygon(points2)
intersect = a&b # calculate the intersect polygon

poly3 = pl.Polygon(intersect[0], color="green") # intersect[0] are the points of the polygon
ax = pl.subplot(122)
ax.add_artist(poly3)
pl.xlim(0, 100)
pl.ylim(0, 100)
pl.show()

Output:

🌐
TutorialsPoint
tutorialspoint.com › numpy › numpy_intersection.htm
NumPy - Intersection
By rounding the arrays to two decimal places, the intersection operation works more accurately despite the small floating-point differences as shown in the example below − · import numpy as np # Define floating-point arrays array1 = np.array([1.234, 2.345, 3.456, 4.567]) array2 = np.array([4.567, 5.678, 6.789]) # Round arrays and find intersection array1_rounded = np.round(array1, 2) array2_rounded = np.round(array2, 2) intersection = np.intersect1d(array1_rounded, array2_rounded) print("Intersection after rounding:", intersection)
🌐
DataCamp
campus.datacamp.com › courses › intro-to-python-for-data-science › chapter-4-numpy
2D NumPy Arrays | Python
The intersection gives us a 2D array with 2 rows and 2 columns: Similarly, you can select the weight of all family members like this: you only want the second row, so put 1 before the comma. You want all columns, so you use a colon after the comma. The intersection gives us the entire second row. Finally, 2D numpy arrays enable you to do element-wise calculations, the same way you did it with 1D numpy arrays.
Top answer
1 of 2
6

If you feed in that sliced 2D array A[:,3:] to np.in1d, it would flatten it to a 1D array and compare with B for occurrences and thus create a 1D mask, which could be reshaped and used for boolean indexing into that sliced array to set the TRUE elements to zeros. A one-liner implementation would look something like this -

A[:,3:][np.in1d(A[:,3:],B).reshape(A.shape[0],-1)] = 0

Sample run -

In [37]: A
Out[37]: 
array([[  1,   1,  10, 101, 102, 103,   0,   0],
       [  2,   2,  10, 102, 108,   0,   0,   0],
       [  3,   3,  11, 101, 102, 106, 107, 108]])

In [38]: np.in1d(A[:,3:],B) # Flattened mask
Out[38]: 
array([ True, False, False, False, False, False,  True, False, False,
       False,  True, False,  True, False,  True], dtype=bool)

In [39]: np.in1d(A[:,3:],B).reshape(A.shape[0],-1) # Reshaped mask
Out[39]: 
array([[ True, False, False, False, False],
       [False,  True, False, False, False],
       [ True, False,  True, False,  True]], dtype=bool)

In [40]: A[:,3:][np.in1d(A[:,3:],B).reshape(A.shape[0],-1)] = 0 # Final code

In [41]: A
Out[41]: 
array([[  1,   1,  10,   0, 102, 103,   0,   0],
       [  2,   2,  10, 102,   0,   0,   0,   0],
       [  3,   3,  11,   0, 102,   0, 107,   0]])

To make things simpler, you could create a view of the flattened A and use the 1D mask obtained from np.in1d to have a more elegant solution. For a solution that changes only the sliced A[:,3:], you can use .flat and then index like so -

A[:,3:].flat[np.in1d(A[:,3:],B)] = 0

For a case when you would like to set matching ones across entire A, you can use .ravel() -

A.ravel()[np.in1d(A,B)] = 0

I know .ravel() is a view and from the docs, it seems .flat doesn't create a copy either, so these should be cheap.

2 of 2
-2

Here's a way to do this without using in1d(). You can use the regular Python in operator with a ravel-ed version of your array:

listed = [aa  in B for aa in A[:, 3:].ravel()]

# mask for unaffected left columns of A
mask1 = np.array([False]*A.shape[0]*3)
mask1.shape = (A.shape[0], 3)

# mask for affected right columns of A
mask2 = np.array(listed)
mask2.shape = (A.shape[0], A.shape[1]-3)

# join masks together so you have a mask with same dimensions as A
mask = np.hstack((mask1, mask2))

result  = A.copy()
result[mask] = 0

Or more succinctly:

listed = [aa  in B for aa in A[:, 3:].ravel()]
listed_array = np.array(listed)
listed.shape = (A.shape[0], A.shape[1]-3)
A[:, 3:][listed_array] = 0

You're probably better off with in1d() but it's nice to know there are other options.