从一个数组中删除元素(如果存在于另一个数组中),保留重复项-NumPy/Python
我有两个阵列从一个数组中删除元素(如果存在于另一个数组中),保留重复项-NumPy/Python,python,numpy,for-loop,unique,Python,Numpy,For Loop,Unique,我有两个阵列A(len为380万)和B(len为20k)。 举一个简单的例子,让我们看看这个例子: A = np.array([1,1,2,3,3,3,4,5,6,7,8,8]) B = np.array([1,2,8]) 现在,我希望得到的数组是: C = np.array([3,3,3,4,5,6,7]) 即,如果在A中找到B中的任何值,则将其从A中删除,如果不保留它。 我想知道是否有方法可以在不使用for循环的情况下执行该操作,因为它是一个很长的数组,因此循环需要很长时间 使用sear
A
(len为380万)和B
(len为20k)。
举一个简单的例子,让我们看看这个例子:
A = np.array([1,1,2,3,3,3,4,5,6,7,8,8])
B = np.array([1,2,8])
现在,我希望得到的数组是:
C = np.array([3,3,3,4,5,6,7])
即,如果在A
中找到B
中的任何值,则将其从A
中删除,如果不保留它。
我想知道是否有方法可以在不使用for
循环的情况下执行该操作,因为它是一个很长的数组,因此循环需要很长时间 使用searchsorted
使用排序的B
,我们可以使用-
从链接的文档中,searchsorted(a,v)
将索引查找到排序数组a
,这样,如果在索引之前插入v
中的相应元素,则a的顺序将被保留。因此,我们假设idx=searchsorted(B,A)
,我们将索引到B
,通过这些:B[idx]
,我们将得到B
的映射版本,对应于A
中的每个元素。因此,将此映射版本与A
进行比较,可以告诉我们A
中的每个元素是否与B
匹配。最后,索引到A
以选择不匹配的
一般情况(B
未排序):
sidx = B.argsort()
idx = np.searchsorted(B,A,sorter=sidx)
idx[idx==len(B)] = 0
out = A[B[sidx[idx]] != A]
如果B
尚未按照先决条件进行排序,请对其进行排序,然后使用建议的方法
或者,我们可以将sorter
参数与searchsorted
-
sidx = B.argsort()
out = A[B[sidx[np.searchsorted(B,A,sorter=sidx)]] != A]
更一般的情况(A
的值高于B
中的值):
sidx = B.argsort()
idx = np.searchsorted(B,A,sorter=sidx)
idx[idx==len(B)] = 0
out = A[B[sidx[idx]] != A]
在AD/isin中使用
我们还可以使用,这是非常直接的(链接文档应该有助于澄清),因为它在B
中为A
中的每个元素查找任何匹配项,然后我们可以使用带反转掩码的布尔索引来查找不匹配项-
A[~np.in1d(A,B)]
与isin相同-
A[~np.isin(A,B)]
使用反转
标志-
A[np.in1d(A,B,invert=True)]
A[np.isin(A,B,invert=True)]
这就解决了当B
不一定排序时的泛型问题。我对numpy不是很熟悉,但是如何使用集合:
C = set(A.flat) - set(B.flat)
编辑:从注释中,集合不能有重复的值
因此,另一种解决方案是使用lambda表达式:
C = np.array(list(filter(lambda x: x not in B, A)))
加上-
如果原始数组A的范围比B大,则会出现“索引超出范围”错误。见:
A = np.array([1,1,2,3,3,3,4,5,6,7,8,8,10,12,14])
B = np.array([1,2,8])
A[B[np.searchsorted(B,A)] != A]
>> IndexError: index 3 is out of bounds for axis 0 with size 3
这是因为np。在本例中,searchsorted
将索引3(B中最后一个之后的一个)指定为在B中插入A中的元素10、12和14的适当位置。因此,在B[np.searchsorted(B,A)]
中会得到一个索引器
为了避免这种情况,一种可能的方法是:
def subset_sorted_array(A,B):
Aa = A[np.where(A <= np.max(B))]
Bb = (B[np.searchsorted(B,Aa)] != Aa)
Bb = np.pad(Bb,(0,A.shape[0]-Aa.shape[0]), method='constant', constant_values=True)
return A[Bb]
def子集排序数组(A,B):
Aa=A[np.式中(数组([3,3,3,4,5,6,7,10,12,14]))
请注意,这也适用于字符串数组和其他类型(对于比较.B
已排序的所有类型?@Divakar:no,但如果需要,我可以对其进行排序,这不是问题。setdiff1d
不会做您需要的事情吗?我可以获得有关这两种方法如何工作的更多信息吗?使用timeit
,似乎第一种方法大约需要两次faster@ThePredator加d注释。这是一个很好且切中要害的答案,但如果a中的值的范围大于B中的值(即,如果a中有较大的值而B中没有),则这不会直接起作用.我将为将来添加一个补充答案reference@vmg说得好!已编辑的解决方案也可以处理这些情况。集合不能包含重复的值。Awesiome。您保存了我的夜晚
# Take only the elements in A that would be inserted in B
Aa = A[np.where(A <= np.max(B))]
# Pad the resulting filter with 'Trues' - I split this in two operations for
# easier reading
Bb = (B[np.searchsorted(B,Aa)] != Aa)
Bb = np.pad(Bb,(0,A.shape[0]-Aa.shape[0]), method='constant', constant_values=True)
# Then you can filter A by Bb
A[Bb]
# For the input arrays above:
>> array([ 3, 3, 3, 4, 5, 6, 7, 10, 12, 14])