【问题标题】:How to use mask indexing on numpy arrays of classes?如何在类的numpy数组上使用掩码索引?
【发布时间】:2016-08-13 19:40:19
【问题描述】:

当使用 numpy array 的自定义类时:

class TestClass:
    active = False

如何使用此处描述的内联屏蔽(布尔索引数组):http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays

直接尝试失败:

items = np.array([TestClass() for _ in range(10)])
items[items.active]

  AttributeError: 'numpy.ndarray' object has no attribute 'active'

有什么建议吗?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    所以你的数组是dtype=object(打印出来)并且每个元素都指向你的类的一个实例:

    items = np.array([TestClass() for _ in range(10)])
    

    现在试试:

    items.active
    

    items 是一个数组; active 是类的属性,而不是对象数组的属性。您的定义不会向ndarray 类添加任何功能。错误不在掩蔽中;它是在尝试获取实例属性。

    像这样的数组上的许多操作都是迭代完成的。这种数组类似于普通的 Python 列表。

    [obj.active for obj in items]
    

    或将其转回数组

    np.array([obj...])
    

    items[[True,False,True,...]] 应该可以工作,但那是因为掩码已经是一个布尔列表或数组。

    =====================

    让我们修改你的类,让它显示一些有趣的东西。请注意,我将 active 分配给实例,而不是像您所做的那样分配给类:

    In [1671]: class TestClass:
          ...:     def __init__(self,val):
          ...:        self.active = bool(val%2)
    
    In [1672]: items = np.array([TestClass(i) for i in range(10)])
    
    In [1674]: items
    Out[1674]: 
    array([<__main__.TestClass object at 0xb106758c>,
           <__main__.TestClass object at 0xb117764c>,
           ...
           <__main__.TestClass object at 0xb269850c>], dtype=object)
    # print of the array isn't interesting.  The class needs a `__str__` method.
    

    这个简单的迭代访问属性:

    In [1675]: [i.active for i in items]
    Out[1675]: [False, True, False, True, False, True, False, True, False, True]
    

    np.frompyfunc 提供了一种更强大的方式来访问数组的每个元素。 operator.attrgetter('active')(i)i.active 的一种功能性方式。

    In [1676]: f=np.frompyfunc(operator.attrgetter('active'),1,1)
    In [1677]: f(items)
    Out[1677]: array([False, True, False, True, False, True, False, True, False, True], dtype=object)
    

    但是当我改变数组的形状时,这个函数的主要优点就显现出来了:

    In [1678]: f(items.reshape(2,5))
    Out[1678]: 
    array([[False, True, False, True, False],
           [True, False, True, False, True]], dtype=object)
    

    注意这个数组是 dtype 对象。这就是frompyfunc 所做的。要获取布尔数组,我们需要更改类型:

    In [1679]: f(items.reshape(2,5)).astype(bool)
    Out[1679]: 
    array([[False,  True, False,  True, False],
           [ True, False,  True, False,  True]], dtype=bool)
    

    np.vectorize 使用frompyfunc,并使 dtype 更加用户友好。但在时间上它有点慢。

    ================

    扩展 Jon 的评论

    In [1702]: class TestClass:
          ...:     def __init__(self,val):
          ...:        self.active = bool(val%2)
          ...:     def __bool__(self):
          ...:         return self.active
          ...:     def __str__(self):
          ...:         return 'TestClass(%s)'%self.active
          ...:     def __repr__(self):
          ...:         return str(self)
    
    In [1707]: items = np.array([TestClass(i) for i in range(5)])
    

    items 现在以信息丰富的方式显示;并转换为字符串:

    In [1708]: items
    Out[1708]: 
    array([TestClass(False), TestClass(True), TestClass(False),
           TestClass(True), TestClass(False)], dtype=object)
    In [1709]: items.astype('S20')
    Out[1709]: 
    array([b'TestClass(False)', b'TestClass(True)', b'TestClass(False)',
           b'TestClass(True)', b'TestClass(False)'], 
          dtype='|S20')
    

    并转换为bool:

    In [1710]: items.astype(bool)
    Out[1710]: array([False,  True, False,  True, False], dtype=bool)
    

    实际上astype 正在将转换方法应用于数组的每个元素。我们还可以定义__int____add__,这表明向自定义类添加功能比向数组类本身添加功能更容易。我不希望获得与原生类型相同的速度。

    【讨论】:

    • def __bool__(self): return self.active 怎么样 - 这似乎在明显的情况下表现得很好......好吧......无论如何astype(bool)......
    • 是的,确实有效; items.astype(bool) 返回相同的数组。如果对象本身实现了适当的方法,则此类数组方法适用于对象数组。向自己的类添加功能比向数组类添加功能更容易。
    猜你喜欢
    • 1970-01-01
    • 2014-10-28
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 2011-11-03
    • 1970-01-01
    • 2022-07-27
    相关资源
    最近更新 更多