Intersection of 2d and 1d Numpy array

房东的猫 提交于 2019-12-18 08:39:52

问题


For every element in array A[:,3:] that is also in array B, I want to set the value to 0, which creates the array result

import numpy as np

A = np.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]])

B = np.array([101, 106, 108])

result = np.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]])

I know there is a way to do this using in1d and broadcasting A as a 1D array, but I have no idea how to go about this.

Any help would be greatly appreciated.


回答1:


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:


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.



来源:https://stackoverflow.com/questions/32481491/intersection-of-2d-and-1d-numpy-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!