Numpy:如何检查ndarray中元组的存在性

3
我在使用numpy数组中的元组时发现了一种奇怪的行为。我想要得到一个布尔值表格,告诉我数组中哪些元组也存在于数组。通常,我会使用inin1d等方法之一。但是这些方法都不起作用,而tuple(a[1]) == b[1,1]却返回True
我按照以下方式填充我的ab
a = numpy.array([(0,0)(1,1)(2,2)], dtype=tuple)

b = numpy.zeros((3,3), dtype=tuple)
for i in range(0,3):
    for j in range(0,3):
        b[i,j] = (i,j)

有人能告诉我如何解决我的问题吗?并请告知为什么这个方法不能按预期工作?

(顺便说一下,我在使用Python2.7和Numpy1.6.2。)


1
这几乎就是:https://dev59.com/wmUq5IYBdhLWcg3wHs6Y#14772313 我认为你可能会在那里找到答案。 - seberg
1个回答

6

为什么这不起作用

简言之,numpy的array.__contains__()实现似乎有问题。在python中,in操作符会在后台调用__contains__()

这意味着a in b等同于b.__contains__(a)

我已经在REPL中加载了您的数组并尝试了以下操作:

>>> b[:,0]
array([(0, 0), (1, 0), (2, 0)], dtype=object)
>>> (0,0) in b[:,0] # we expect it to be true
False
>>> (0,0) in list(b[:,0]) # this shouldn't be different from the above but it is
True
>>> 

如何解决

我不明白你的列表推导式是如何工作的,因为a[x]是一个元组,b[:,:]是一个二维矩阵,所以它们肯定不相等。但我假设你想使用in而不是==。如果我错了,你有不同的意思,请纠正我。

第一步是将b从二维数组转换为一维数组,这样我们就可以线性地筛选它,并将其转换为列表,以避免numpy的破损的array.__contains()问题,代码如下:

bb = list(b.reshape(b.size))

更好的做法是将其作为 set 进行处理,因为元组是不可变的,而在集合中使用 in 操作是 O(1) 而非列表的 O(n) 行为。

>>> bb = set(b.reshape(b.size))
>>> print bb
set([(0, 1), (1, 2), (0, 0), (2, 1), (1, 1), (2, 0), (2, 2), (1, 0), (0, 2)])
>>> 

下一步,我们只需使用列表推导式来生成布尔值表。
>>> truth_table = [tuple(aa) in bb for aa in a]
>>> print truth_table
[True, True, True]
>>> 

完整的代码如下:
def contained(a,b):
    bb = set(b.flatten())
    return [tuple(aa) in bb for aa in a]

很高兴知道它的破碎是事实。最终我使用了这个答案提供的“完整代码”示例。非常感谢!还有一个问题:为什么您选择使用 reshape 而不是 flatten - pdresselhaus
因为我只使用过很少的numpy,而且这是我在通过help(numpy.array)搜索时找到的第一件事:P 我不确定破碎是否是事实,但看起来确实是这样,特别是在seberg对你的问题的评论中的链接。我将修改答案以使用“flatten”。 - entropy
还有另一个问题:为什么 x,y = zip(*a)s = set(zip(x,y)) 起作用,而通常列表是可变的,因此不能直接转换为集合? - pdresselhaus
如果列表只包含不可变对象,则可以将其转换为集合。因此,您无法将列表添加到集合中,但是例如您可以调用set(range(30))。由于zip生成元组列表,因此您应该能够将该结果转换为集合。当然,前提是这些元组本身不包含任何可变内容。 - entropy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接