Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 测试Numpy数组是否包含给定行_Python_Numpy - Fatal编程技术网

Python 测试Numpy数组是否包含给定行

Python 测试Numpy数组是否包含给定行,python,numpy,Python,Numpy,是否有一种Pythonic和有效的方法来检查Numpy数组是否包含给定行的至少一个实例?“高效”是指在找到第一个匹配行时终止,而不是迭代整个数组,即使已经找到结果 对于Python数组,如果数组中的行:,这可以非常干净地完成,但这并不像我期望的Numpy数组那样工作,如下所示 对于Python数组: >>> a = [[1,2],[10,20],[100,200]] >>> [1,2] in a True >>> [1,20] in a Fa

是否有一种Pythonic和有效的方法来检查Numpy数组是否包含给定行的至少一个实例?“高效”是指在找到第一个匹配行时终止,而不是迭代整个数组,即使已经找到结果

对于Python数组,如果数组中的行:,这可以非常干净地完成,但这并不像我期望的Numpy数组那样工作,如下所示

对于Python数组:

>>> a = [[1,2],[10,20],[100,200]]
>>> [1,2] in a
True
>>> [1,20] in a
False
但是Numpy数组给出了不同的、看起来相当奇怪的结果。(
\uuuu包含
ndarray
的方法似乎未记录。)

我想

equal([1,2], a).all(axis=1)   # also,  ([1,2]==a).all(axis=1)
# array([ True, False, False], dtype=bool)
将列出匹配的行。正如Jamie指出的,要知道是否至少存在一行,请使用
any

equal([1,2], a).all(axis=1).any()
# True
旁白:
我怀疑
中的
(和
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

或使用视图:

>>> any((a[:]==[1,2]).all(1))
True
>>> any((a[:]==[1,20]).all(1))
False
或通过numpy列表生成(可能非常慢):

或使用numpy逻辑功能:

any(np.equal(a,[1,2]).all(1))
如果您对这些进行计时:

import numpy as np
import time

n=300000
a=np.arange(n*3).reshape(n,3)
b=a.tolist()

t1,t2,t3=a[n//100][0],a[n//2][0],a[-10][0]

tests=[ ('early hit',[t1, t1+1, t1+2]),
        ('middle hit',[t2,t2+1,t2+2]),
        ('late hit', [t3,t3+1,t3+2]),
        ('miss',[0,2,0])]

fmt='\t{:20}{:.5f} seconds and is {}'     

for test, tgt in tests:
    print('\n{}: {} in {:,} elements:'.format(test,tgt,n))

    name='view'
    t1=time.time()
    result=(a[...]==tgt).all(1).any()
    t2=time.time()
    print(fmt.format(name,t2-t1,result))

    name='python list'
    t1=time.time()
    result = True if tgt in b else False
    t2=time.time()
    print(fmt.format(name,t2-t1,result))

    name='gen over numpy'
    t1=time.time()
    result=any((tgt == x).all() for x in a)
    t2=time.time()
    print(fmt.format(name,t2-t1,result))

    name='logic equal'
    t1=time.time()
    np.equal(a,tgt).all(1).any()
    t2=time.time()
    print(fmt.format(name,t2-t1,result))
您可以看到,命中或未命中,numpy例程以相同的速度搜索数组。在
操作符中的Python
对于早期的成功来说可能要快得多,如果您必须遍历整个数组,那么生成器就是个坏消息

以下是300000 x 3元素阵列的结果:

early hit: [9000, 9001, 9002] in 300,000 elements:
    view                0.01002 seconds and is True
    python list         0.00305 seconds and is True
    gen over numpy      0.06470 seconds and is True
    logic equal         0.00909 seconds and is True

middle hit: [450000, 450001, 450002] in 300,000 elements:
    view                0.00915 seconds and is True
    python list         0.15458 seconds and is True
    gen over numpy      3.24386 seconds and is True
    logic equal         0.00937 seconds and is True

late hit: [899970, 899971, 899972] in 300,000 elements:
    view                0.00936 seconds and is True
    python list         0.30604 seconds and is True
    gen over numpy      6.47660 seconds and is True
    logic equal         0.00965 seconds and is True

miss: [0, 2, 0] in 300,000 elements:
    view                0.00936 seconds and is False
    python list         0.01287 seconds and is False
    gen over numpy      6.49190 seconds and is False
    logic equal         0.00965 seconds and is False
对于3000000 x 3阵列:

early hit: [90000, 90001, 90002] in 3,000,000 elements:
    view                0.10128 seconds and is True
    python list         0.02982 seconds and is True
    gen over numpy      0.66057 seconds and is True
    logic equal         0.09128 seconds and is True

middle hit: [4500000, 4500001, 4500002] in 3,000,000 elements:
    view                0.09331 seconds and is True
    python list         1.48180 seconds and is True
    gen over numpy      32.69874 seconds and is True
    logic equal         0.09438 seconds and is True

late hit: [8999970, 8999971, 8999972] in 3,000,000 elements:
    view                0.09868 seconds and is True
    python list         3.01236 seconds and is True
    gen over numpy      65.15087 seconds and is True
    logic equal         0.09591 seconds and is True

miss: [0, 2, 0] in 3,000,000 elements:
    view                0.09588 seconds and is False
    python list         0.12904 seconds and is False
    gen over numpy      64.46789 seconds and is False
    logic equal         0.09671 seconds and is False

这似乎表明
np.equal
是实现这一点的最快的纯numpy方法…

如果您真的想在第一次出现时停止,您可以编写一个循环,如:

import numpy as np

needle = np.array([10, 20])
haystack = np.array([[1,2],[10,20],[100,200]])
found = False
for row in haystack:
    if np.all(row == needle):
        found = True
        break
print("Found: ", found)

但是,我强烈怀疑,它将比使用numpy例程对整个数组执行此操作的其他建议慢得多。

Numpys
\uuuu包含\uuuu
,这可能只有在
b
是标量时才是正确的(这有点毛茸茸的,但我相信——只有在1.7或更高版本中才能这样工作——这将是正确的通用方法
(a==b).all(np.arange(a.ndim-b.ndim,a.ndim)).any()
,这对
a
b
维度的所有组合都有意义)

编辑:只是想澄清一下,当涉及广播时,这不一定是预期的结果。还有人可能会争辩说,它应该像
np.inad
那样单独处理
a
中的项目。我不确定它是否有一个明确的工作方式

现在,您希望numpy在找到第一个匹配项时停止。此时不存在此AFAIK。这很困难,因为numpy主要基于UFUNC,UFUNC在整个阵列上执行相同的操作。 Numpy确实优化了这些类型的缩减,但只有当被缩减的数组已经是布尔数组(即
np.ones(10,dtype=bool.any()
)时,这种方法才有效

否则它将需要一个特殊的函数来处理不存在的
。\uuuuu包含\uuuuu
。这可能看起来有些奇怪,但您必须记住,numpy支持许多数据类型,并且有一个更大的机器来选择正确的数据类型并选择正确的函数来处理它。因此,换句话说,ufunc机器无法完成这项工作,因此
\uuuuuu包含\uuuuu
或这样的数据类型实际上并不是那么简单

当然,您可以用python编写它,或者因为您可能知道自己的数据类型,所以自己用Cython/C编写它非常简单


也就是说。通常对这些事情使用基于排序的方法要好得多。这有点乏味,而且对于
lexsort
,没有
searchsorted
这样的东西,但它是有效的(如果你愿意,你也可以滥用
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
执行排序,效果也会更好).重要提示:为了安全起见,您必须执行
np.ascontiguousarray
。它通常不会执行任何操作,但如果执行,则将是一个巨大的潜在错误。

我将建议的解决方案与进行了比较,发现如果您在一个长的未排序列表中查找2元组

np.any(np.all(a==b,轴=1))
是最快的解决方案。如果在前几行中找到匹配项,则显式短路循环总是可以更快

复制绘图的代码:

将numpy导入为np
导入性能图
目标=[6,23]
def设置(n):
返回np.random.randint(0,100,(n,2))
def any_all(数据):
返回np.any(np.all(target==数据,axis=1))
def tolist(数据):
返回data.tolist()中的目标
def循环(数据):
对于数据中的行:
如果np.all(行==目标):
返回真值
返回错误
第(一)款:
s=np.ascontiguousarray(a).view([('',a.dtype)]*a.shape[-1]).ravel()
s、 排序()
t=np.ascontiguousarray(target).view(s.dtype)
ind=s.t(t)
返回(s[ind]==t)[0]
perfplot.save(
“out02.png”,
设置=设置,
内核=[any_all,tolist,loop,searchsorted],
n_范围=[2**k表示范围(2,20)中的k],
xlabel=“len(数组)”,
)

+1太好了!你必须用
np.any(…)来包装它
获取单个成员布尔值。谢谢。但这将遍历整个数组,并在内存中分配一个包含所有结果的新数组,然后检查它是否为空。高效的实现将在找到第一个匹配行后立即停止并返回True。我已将问题编辑为c请澄清我所说的“高效”是什么意思。谢谢,但我正在寻找一个在找到第一个匹配行后终止的实现,而不是遍历整个行
early hit: [90000, 90001, 90002] in 3,000,000 elements:
    view                0.10128 seconds and is True
    python list         0.02982 seconds and is True
    gen over numpy      0.66057 seconds and is True
    logic equal         0.09128 seconds and is True

middle hit: [4500000, 4500001, 4500002] in 3,000,000 elements:
    view                0.09331 seconds and is True
    python list         1.48180 seconds and is True
    gen over numpy      32.69874 seconds and is True
    logic equal         0.09438 seconds and is True

late hit: [8999970, 8999971, 8999972] in 3,000,000 elements:
    view                0.09868 seconds and is True
    python list         3.01236 seconds and is True
    gen over numpy      65.15087 seconds and is True
    logic equal         0.09591 seconds and is True

miss: [0, 2, 0] in 3,000,000 elements:
    view                0.09588 seconds and is False
    python list         0.12904 seconds and is False
    gen over numpy      64.46789 seconds and is False
    logic equal         0.09671 seconds and is False
import numpy as np

needle = np.array([10, 20])
haystack = np.array([[1,2],[10,20],[100,200]])
found = False
for row in haystack:
    if np.all(row == needle):
        found = True
        break
print("Found: ", found)
# 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