有没有一种Pythonic高效的方法来检查Numpy数组是否包含给定行的至少一个实例? “有效”是指它在找到第一个匹配行时终止,而不是遍历整个数组,即使已经找到结果也是如此。
使用Python数组,可以使用if row in array:
非常干净地完成此操作,但这不符合我对Numpy数组的预期,如下所示。
使用Python数组:
>>> a = [[1,2],[10,20],[100,200]]
>>> [1,2] in a
True
>>> [1,20] in a
False
但是Numpy数组给出的结果却不同,而且看起来很奇怪。 (
__contains__
的ndarray
方法似乎没有记录。)>>> a = np.array([[1,2],[10,20],[100,200]])
>>> np.array([1,2]) in a
True
>>> np.array([1,20]) in a
True
>>> np.array([1,42]) in a
True
>>> np.array([42,1]) in a
False
最佳答案
Numpys __contains__
is, at the time of writing this, (a == b).any()
仅在b
是标量的情况下才是正确的(它有点毛,但我相信–仅在1.7或更高版本中如此工作–这将是正确的通用方法(a == b).all(np.arange(a.ndim - b.ndim, a.ndim)).any()
,对于所有的组合都有意义a
和b
维度)...
编辑:请明确一点,当涉及广播时,这不一定是预期的结果。也可能有人认为它应该像a
一样单独处理np.in1d
中的项目。我不确定是否应该有一种明确的方法。
现在,您希望numpy在找到第一个匹配项时停止。该AFAIK目前不存在。这很困难,因为numpy主要基于ufunc,它们在整个数组上执行相同的操作。
Numpy确实优化了这种类型的缩减,但是有效的是,仅当要缩减的数组已经是 bool 数组(即np.ones(10, dtype=bool).any()
)时,该选项才有效。
否则,它将需要不存在的__contains__
特殊功能。这似乎很奇怪,但是您必须记住numpy支持许多数据类型,并且具有更大的机制来选择正确的数据类型并选择正确的函数来处理它。因此,换句话说,ufunc机制无法做到这一点,并且由于数据类型的原因,特别是实现__contains__
或类似的实现实际上并不是那么简单。
您当然可以用python编写它,或者因为您可能知道数据类型,所以用Cython/C编写它非常简单。
那就是。无论如何,对这些事情使用基于排序的方法通常要好得多。这有点乏味,而且没有searchsorted
的lexsort
这样的东西,但是它可以工作(如果您愿意,也可以滥用scipy.spatial.cKDTree
)。假设您只想沿最后一个轴进行比较:
# Unfortunatly you need to use structured arrays:
sorted = np.ascontiguousarray(a).view([('', a.dtype)] * a.shape[-1]).ravel()
# Actually at this point, you can also use np.in1d, if you already have many b
# then that is even better.
sorted.sort()
b_comp = np.ascontiguousarray(b).view(sorted.dtype)
ind = sorted.searchsorted(b_comp)
result = sorted[ind] == b_comp
这也适用于
b
数组,如果保留排序后的数组,则当b
保持相同时一次对a
中的单个值(行)进行处理,也会更好得多(否则,我只需要np.in1d
将其视为一个rearray)。重要提示:为了安全起见,您必须执行np.ascontiguousarray
。它通常什么也不做,但是如果这样做,否则将是一个很大的潜在错误。关于python - 测试Numpy数组是否包含给定的行,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14766194/