【问题标题】:Handling attributes of a class within a numpy array处理 numpy 数组中类的属性
【发布时间】:2015-02-27 21:09:36
【问题描述】:

我想处理类属性不通过 Python for 循环。要处理大型数组,numpy 是最好/最快的,但是否可以访问 numpy 数组中的类属性?考虑以下简单的代码:

import numpy as np

class MyClass():
    def __init__(self):
        self.myvar1 = 10
        self.myvar2 = 20

myarray1 = np.arange(0, 1000, 1)
myarray2 = np.array([MyClass() for i in range(1000)])

myarray1 的所有值都可以通过一行轻松修改:

myarray1 += 5

但是我如何访问myarray2 中所有MyClass 实例中的myvar1 并一次性修改它? (甚至可能吗?)我知道以下内容不起作用,但它给出了我想要实现的目标:

myarray2.myvar1 += 5
myarray2[myarray2.myvar1] += 5

我一直在四处寻找解决方案,我能找到的最接近的是 numpy 的 recarray,它可以模仿 Python 类,但它似乎不是我的解决方案,因为我使用的类是一个子类(确切地说是一个 pyglet Sprite),所以我确实需要使用 Python 类。

编辑

跟进 hpaulj 评论,我正在尝试使用该类的矢量化函数来更新其属性。这是更新类的所有实例的有效方法吗?

class MyClass():
    def __init__(self):
        self.myvar1 = 10
        self.myvar2 = 20
    def modifyvar(self):
        self.myvar1 += 5
        return self

vecfunc = np.vectorize(MyClass.modifyvar)
myarray2 = np.array([MyClass() for i in range(1000)])
myarray2 = vecfunc(myarray2)

但是,另一个问题出现了:使用此代码时,myarray2[0].myvar1 返回 20 而不是 15! myarray2[1].myvar1 确实返回 15,数组的其余部分也是如此。为什么myarray2[0] 在这里不一样?


解决方案

向量化类的函数允许在没有 for 循环的情况下处理它的几个实例的属性。解决方案代码:

class MyClass():
    def __init__(self):
        self.myvar1 = 10
        self.myvar2 = 20
    def modifyvar(self):
        self.myvar1 += 5
        return self

vecfunc = np.vectorize(MyClass.modifyvar, otypes=[object])
myarray2 = np.array([MyClass() for i in range(1000)])
vecfunc(myarray2)

注意:在使用vectorize和处理对象时添加otype=[object]

【问题讨论】:

  • 是您想要避免 for 循环的唯一原因,因为您希望/期望它在没有循环的情况下更快?
  • 这是主要原因之一,但即使它没有提高性能,我仍然想知道是否可以访问 numpy 数组中对象的属性。
  • myarray2dtype=object。因此,其数据缓冲区中的每个条目都是指向内存中其他位置的实例的指针。该类型数组的矢量化(使用编译代码)操作非常初级。
  • recarray 是结构化数组的覆盖。数据存储为恒定大小的“元组”(与数字或指针相反)。使用结构化数组,您可以使用 myarray3['myvar1'] +=1
  • 感谢您的帮助。我看不出recarray 是如何一次更新所有python 类实例的,你能解释一下吗?对于矢量化操作,请查看我的编辑,如果我朝着正确的方向前进,请告诉我。

标签: python class numpy attributes


【解决方案1】:

modifyvar 对第一个元素的额外应用是由于vectorize 试图确定要返回的数组类型。指定 otypes 可以解决这个问题:

vecfunc = np.vectorize(MyClass.modifyvar,otypes=[object])

有了这个'inplace'修饰符,你不需要注意返回的内容:

vecfunc(myarray2)

足够了。

来自vectorize 文档:

vectorized的输出的数据类型是通过调用来确定的 具有输入的第一个元素的函数。这是可以避免的 通过指定 otypes 参数。

如果您定义了 add5 方法,例如:

    def add5(self):
        self.myvar1 += 5
        return self.myvar1

然后

vecfunc = np.vectorize(MyClass.add5,otypes=[int])
vecfunc(myarray2)

会返回一个数值数组,同时修改myarray2

array([15, 15, 15, 15, 15, 15, 15, 15, 15, 15])

显示我使用的值:

[x.myvar1 for x in myarray2]

我真的应该定义一个矢量化的“打印”。

这看起来像是vectorize 的更好应用之一。它不会为您提供任何编译速度,但它确实允许您在对实例进行操作时使用数组表示法和广播。例如 vecfunc(myarray2.reshape(2,5)) 返回一个 (2,5) 值数组。

【讨论】:

  • 非常好!与使用 for 循环相比,它可以工作并且性能大大提高。谢谢你:)
  • 可能夸大了它的性能,需要进一步测试。但它仍然是处理类的好方法
  • wiki.scipy.org/Cookbook/Obarray - 建议将实例属性存储在记录数组中,并动态创建实例以访问方法。
猜你喜欢
  • 2014-06-04
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
  • 2012-09-11
  • 2013-06-01
  • 2019-08-22
相关资源
最近更新 更多