用Pythonic方法测试行是否在数组中

11 投票
5 回答
7160 浏览
提问于 2025-04-16 20:44

这看起来是个简单的问题,但我一直找不到好的答案。

我想用一种“Python风格”的方法来检查一个二维的numpy数组里是否包含某一行。比如说:

myarray = numpy.array([[0,1],
                       [2,3],
                       [4,5]])

myrow1 = numpy.array([2,3])
myrow2 = numpy.array([2,5])
myrow3 = numpy.array([0,3])
myrow4 = numpy.array([6,7])

给定一个叫myarray的数组,我想写个函数,如果我测试myrow1,它返回True;如果我测试myrow2、myrow3和myrow4,它返回False。

我试过用“in”这个关键字,但结果并不是我预期的:

>>> myrow1 in myarray
True
>>> myrow2 in myarray
True
>>> myrow3 in myarray
True
>>> myrow4 in myarray
False

它似乎只检查是否有一个或多个元素相同,而不是检查所有元素是否都相同。有人能解释一下这是为什么吗?

我可以逐个元素地进行这个测试,像这样:

def test_for_row(array,row):
    numpy.any(numpy.logical_and(array[:,0]==row[0],array[:,1]==row[1]))

但这样做不太符合Python的风格,如果行里的元素很多,这样做就会变得很麻烦。肯定有更优雅的解决方案。任何帮助都很感谢!

5 个回答

1

这是对@maz的解决方案的一个扩展,能够更优雅地处理浮点数的问题,因为在某些情况下,严格的相等比较会失败:

import numpy as np

def test_for_row(myarray,row):
    return any(np.allclose(row,x) for x in myarray)

详情请查看 http://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html。另外,提醒一下,要小心不要使用像 from numpy import * 这样的写法,因为 np.any 和 Python 自带的 any 会给出不同的结果,前者是错误的。

5

下面这个StackOverflow的问题应该能帮到你,简单来说,你可以使用:

any((myrow1 == x).all() for x in myarray)

在Python列表中使用Numpy数组?

3

你可以简单地把你的测试行从数组中减去。然后找出结果中为零的元素,并对每一列进行求和。那些求和结果等于列数的地方就是匹配的地方。

举个例子:

In []: A= arange(12).reshape(4, 3)
In []: A
Out[]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
In []: 3== (0== (A- [3, 4, 5])).sum(1)
Out[]: array([False,  True, False, False], dtype=bool)

更新: 根据评论和其他回答来看,
Paul的建议确实能让代码更简洁:

In []: ~np.all(A- [3, 4, 5], 1)
Out[]: array([False,  True, False, False], dtype=bool)

JoshAdel的回答更强调了如何以100%可靠的方式判断相等的问题。所以,我的回答显然只适用于那些可以明确判断相等的情况。

更新 2: 但是正如Emma所发现的,确实存在一些特殊情况,Paul的解决方案可能会得出错误的结果。

撰写回答