我想检查我的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")
答案 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问题,甚至还有一些关于获取或测试这些数组元素属性的问题。一般来说,这样的数组行为很像列表。在大多数情况下,您必须迭代数组,就像它是一个列表一样。您可以使用add
,multiply
等数字数组执行的大多数酷事都不适用。或者您的对象必须实现特定的方法,以便将操作传播到对象。
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) ])