用Pythonic方法测试行是否在数组中
这看起来是个简单的问题,但我一直找不到好的答案。
我想用一种“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 个回答
这是对@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
会给出不同的结果,前者是错误的。
下面这个StackOverflow的问题应该能帮到你,简单来说,你可以使用:
any((myrow1 == x).all() for x in myarray)
你可以简单地把你的测试行从数组中减去。然后找出结果中为零的元素,并对每一列进行求和。那些求和结果等于列数的地方就是匹配的地方。
举个例子:
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
的解决方案可能会得出错误的结果。