在数组中的对象上设置属性的最有效方法

2024-04-19 16:51:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是表示网格的大型数组,每个元素都是具有x,y属性的Cell对象。你知道吗

我不确定初始化数组的最有效方法,我的基本实现是:

# X,Y dimensions of grid:
Gx = 3000
Gy = 4000

    # Array to create
    A = numpy.ndarray(shape=(int(self.Gx),int(self.Gy)),dtype=object)

for y in range(0,int(self.Gy)):
             for x in range (0,int(self.Gx)):       
              c = Cell(1,x,y,1)
              A.itemset((x,y),c)

显然,这对于大型阵列是不有效的。我知道如何创建大型对象数组并使用矢量化一次访问所有对象。我搞不懂的是如何在一个函数中应用一个索引数组(通过A.index),而不需要遍历整个数组。你知道吗

每个Cell对象都有一个setX和setY函数,我可以将索引数组传递给函数,以便在一行中设置每个Cell的y值吗?你知道吗


Tags: 对象方法函数inself网格元素for
1条回答
网友
1楼 · 发布于 2024-04-19 16:51:59

定义一个简单类:

class Cell():
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def setX(self,x):
        self.x=x
    def __repr__(self):
        return f'Cell({self.x},{self.y})'

创建这些对象数组的一种方法:

In [653]: f = np.frompyfunc(Cell, 2, 1)
In [654]: arr = f(np.arange(3)[:,None], np.arange(4))
In [655]: arr
Out[655]: 
array([[Cell(0,0), Cell(0,1), Cell(0,2), Cell(0,3)],
       [Cell(1,0), Cell(1,1), Cell(1,2), Cell(1,3)],
       [Cell(2,0), Cell(2,1), Cell(2,2), Cell(2,3)]], dtype=object)
In [656]: arr.shape
Out[656]: (3, 4)

创建相同对象的列表方式:

In [658]: [[Cell(i,j) for i in range(3)] for j in range(4)]
Out[658]: 
[[Cell(0,0), Cell(1,0), Cell(2,0)],
 [Cell(0,1), Cell(1,1), Cell(2,1)],
 [Cell(0,2), Cell(1,2), Cell(2,2)],
 [Cell(0,3), Cell(1,3), Cell(2,3)]]

一些比较时间:

In [659]: timeit arr = f(np.arange(3)[:,None], np.arange(4))
13.5 µs ± 73.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [660]: timeit [[Cell(i,j) for i in range(3)] for j in range(4)]
8.3 µs ± 115 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [661]: timeit arr = f(np.arange(300)[:,None], np.arange(400))
64.9 ms ± 293 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [662]: timeit [[Cell(i,j) for i in range(300)] for j in range(400)]
78 ms ± 2.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

对于大型集合,frompyfunc方法具有适度的速度优势。你知道吗

从所有单元格获取值:

In [664]: np.frompyfunc(lambda c: c.x, 1, 1)(arr)
Out[664]: 
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2]], dtype=object)

使用SetX方法:

In [665]: np.frompyfunc(Cell.setX, 2, 1)(arr, np.arange(12).reshape(3,4))
Out[665]: 
array([[None, None, None, None],
       [None, None, None, None],
       [None, None, None, None]], dtype=object)
In [666]: arr
Out[666]: 
array([[Cell(0,0), Cell(1,1), Cell(2,2), Cell(3,3)],
       [Cell(4,0), Cell(5,1), Cell(6,2), Cell(7,3)],
       [Cell(8,0), Cell(9,1), Cell(10,2), Cell(11,3)]], dtype=object)

SetX不返回任何内容,因此函数调用生成的数组是allNone。但是它修改了arr的所有元素。与列表理解一样,我们通常不使用frompyfunc调用来产生副作用,但这是可能的。你知道吗

np.vectorize,在它的默认(和原始)形式中,只使用frompyfunc,并调整返回的数据类型。frompyfunc总是返回对象数据类型。较新版本的vectorize有一个signature参数,允许我们向函数传递数组(而不是标量),然后返回数组。但这个过程更慢。你知道吗

像这样定义对象数组可能会使代码看起来更干净、更有条理,但它们在速度上永远无法与数值numpy数组相匹配。你知道吗


给定Cell的定义,我可以将属性设置为数组,例如

Cell(np.arange(3), np.zeros((3,4)))

但是要设置单元格数组的值,我必须首先构造一个对象数组:

In [676]: X = np.zeros(3, object)
In [677]: for i,row in enumerate(np.arange(6).reshape(3,2)): X[i]=row
In [678]: X
Out[678]: array([array([0, 1]), array([2, 3]), array([4, 5])], dtype=object)
In [679]: np.frompyfunc(Cell.setX, 2, 1)(arr, X[:,None])
Out[679]: 
array([[None, None, None, None],
       [None, None, None, None],
       [None, None, None, None]], dtype=object)
In [680]: arr
Out[680]: 
array([[Cell([0 1],0), Cell([0 1],1), Cell([0 1],2), Cell([0 1],3)],
       [Cell([2 3],0), Cell([2 3],1), Cell([2 3],2), Cell([2 3],3)],
       [Cell([4 5],0), Cell([4 5],1), Cell([4 5],2), Cell([4 5],3)]],
      dtype=object)

我无法传递(3,2)数组:

In [681]: np.frompyfunc(Cell.setX, 2, 1)(arr, np.arange(6).reshape(3,2))
ValueError: operands could not be broadcast together with shapes (3,4) (3,2) 

numpy优先使用多维(数字)数组。创建和使用对象数据类型数组需要一些特殊技巧。你知道吗

相关问题 更多 >