Python:检查numpy数组是否包含具有特定属性的对象

时间:2016-09-30 00:56:33

标签: python python-2.7 numpy

我想检查我的numpy数组中是否有任何具有特定属性的对象:

class Test:
def __init__(self, name):
    self.name = name

l = numpy.empty( (2,2), dtype=object)
l[0][0] = Test("A")
l[0][1] = Test("B")
l[1][0] = Test("C")
l[1][1] = Test("D")

我知道下面的代码行是为列表工作的,但numpy数组的替代流程是什么?

print numpy.any(l[:,0].name == "A")

3 个答案:

答案 0 :(得分:1)

一种简单的方法是通过继承Numpy的ndarray对象来创建数组对象。然后使用自定义函数根据name属性检查对象是否存在:

In [71]: class Myarray(np.ndarray):
   ....:         def __new__(cls, inputarr):
   ....:                 obj = np.asarray(inputarr).view(cls)
   ....:                 return obj
   ....:         def custom_contain(self, name):
   ....:                 return any(obj.name == name for obj in self.flat)

演示:

In [4]: A = np.empty((2,2),dtype=object)    
In [8]: A.flat[:] = [Test("A"), Test("B"), Test("C"), Test("D")]

In [9]: A
Out[9]: 
array([[<__main__.Test instance at 0x7fae0a14ddd0>,
        <__main__.Test instance at 0x7fae0a14de18>],
       [<__main__.Test instance at 0x7fae0a14de60>,
        <__main__.Test instance at 0x7fae0a14dea8>]], dtype=object)

In [11]: A = Myarray(A)

In [12]: A.custom_contain('C')
Out[12]: True

In [13]: A.custom_contain('K')
Out[13]: False

答案 1 :(得分:1)

关于对象dtype数组有很多SO问题,甚至还有一些关于获取或测试这些数组元素属性的问题。一般来说,这样的数组行为很像列表。在大多数情况下,您必须迭代数组,就像它是一个列表一样。您可以使用addmultiply等数字数组执行的大多数酷事都不适用。或者您的对象必须实现特定的方法,以便将操作传播到对象。

In [15]: class Test:
    ...:     def __init__(self,name):
    ...:         self.name=name
    ...:     def __repr__(self):   # added for nice display
    ...:         return 'Test:%s'%self.name
    ...:     
In [16]: A = np.empty((2,2),dtype=object)

我可以使用flat[:]一次分配所有值并列出:

In [17]: A.flat[:]=[Test('A'),Test('B'),Test('C'),Test('D')]

In [18]: A      # try this display without the `repr`
Out[18]: 
array([[Test:A, Test:B],
       [Test:C, Test:D]], dtype=object)

这返回False,因为我没有为类定义cmp; Test('A')==Test('A')也是假的。

In [19]: Test('A') in A
Out[19]: False


In [20]: A[0,1].name
Out[20]: 'B'

这是真的,因为它是身份测试

In [21]: A[0,1] in A
Out[21]: True

由于A是2d,因此对它的简单列表理解不起作用,至少不用于测试属性。在这种情况下,a是一行A,一个1d对象数组:

In [23]: [a.name for a in A]
...
AttributeError: 'numpy.ndarray' object has no attribute 'name'

获取我必须在A.flat上迭代的名称;我可以将in测试应用于结果列表:

In [24]: [a.name for a in A.flat]
Out[24]: ['A', 'B', 'C', 'D']
In [25]: 'B' in [a.name for a in A.flat]
Out[25]: True

np.vectorize是一种编写在各种形状的数组上运行的函数的方法。它使用np.frompyfunc,在这种情况下,如果不是更好的话也可以。

In [27]: foo = np.frompyfunc(lambda a: a.name, 1,1)
In [28]: foo(A)
Out[28]: 
array([['A', 'B'],
       ['C', 'D']], dtype=object)
In [29]: 'C' in foo(A)
Out[29]: True

或者我可以定义执行name相等测试的版本。请注意,这需要2个输入

In [30]: bar = np.frompyfunc(lambda a,b: b == a.name, 2, 1)

In [32]: bar(A,'C')
Out[32]: 
array([[False, False],
       [True, False]], dtype=object)

我甚至可以通过广播测试2个阵列:

In [37]: bar(A,np.array(['A','D'])[:,None,None])
Out[37]: 
array([[[True, False],
        [False, False]],

       [[False, False],
        [False, True]]], dtype=object)

frompyfunc按照[a for a in A.flat]进行迭代,但速度稍快,并且在任务中抛出了numpy广播的所有功能。

答案 2 :(得分:0)

我显然不精通numpy,但你不能做一些像:

numpy.any([ x.name=='A' for x in l[:,0] ])

编辑: (Google告诉我)可以使用nditer迭代数组;这就是你想要的吗?

numpy.any([ x.name=='A' for x in numpy.nditer(l) ])