Python 使用唯一的对象实例创建NumPy

Python 使用唯一的对象实例创建NumPy,python,python-3.x,numpy,numpy-ndarray,Python,Python 3.x,Numpy,Numpy Ndarray,我想使用numpy.full()创建一个numpy.ndarray完整的自定义类的唯一实例。我目前的尝试是: import numpy as np from custom_class import CustomClass size_x = 4 size_y = 5 my_array = np.full((size_x, size_y), CustomClass('value')) 问题是,当我运行这段代码时,输出是一个numpy.ndarray,其中包含对同一对象的size\uxxsize

我想使用
numpy.full()
创建一个
numpy.ndarray
完整的自定义类的唯一实例。我目前的尝试是:

import numpy as np
from custom_class import CustomClass

size_x = 4
size_y = 5

my_array = np.full((size_x, size_y), CustomClass('value'))
问题是,当我运行这段代码时,输出是一个
numpy.ndarray
,其中包含对同一对象的
size\ux
x
size\uy
的引用。查看示例输出:

array([[<hexgridcell.HexGridCell object at 0x000001C3B5B18BE0>,
        <hexgridcell.HexGridCell object at 0x000001C3B5B18BE0>,
        <hexgridcell.HexGridCell object at 0x000001C3B5B18BE0>,
        <hexgridcell.HexGridCell object at 0x000001C3B5B18BE0>, ...
数组([,,
,
,
, ...
这里列出的地址都清楚地指向内存中的同一个位置,进一步的调查得出结论,它们确实指向同一个对象实例。我如何才能让一个
numpy.ndarray
以这种方式填充唯一的实例?

一个示例类:(一个好的问题可以提供类似的内容)


full
在所有插槽中放置相同的内容-当然,因为
Foo
只调用一次

In [103]: np.full((2,3), Foo(1,2))                                                       
Out[103]: 
array([[Foo (1, 2), Foo (1, 2), Foo (1, 2)],
       [Foo (1, 2), Foo (1, 2), Foo (1, 2)]], dtype=object)
在前面的问题中,我发现
frompyfunc
非常方便,并且比更显式的numpy循环快2倍:

列表方法:

In [107]: [[Foo(i,j) for j in range(4)] for i in range(3)]                               
Out[107]: 
[[Foo (0, 0), Foo (0, 1), Foo (0, 2), Foo (0, 3)],
 [Foo (1, 0), Foo (1, 1), Foo (1, 2), Foo (1, 3)],
 [Foo (2, 0), Foo (2, 1), Foo (2, 2), Foo (2, 3)]]
一些时间安排:

In [108]: timeit f(np.arange(3)[:,None], np.arange(4))                                   
14.3 µs ± 469 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [109]: timeit [[Foo(i,j) for j in range(4)] for i in range(3)]                        
7.59 µs ± 18.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [110]: timeit np.array([[Foo(i,j) for j in range(4)] for i in range(3)])              
31.3 µs ± 1.69 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
使用对象数组执行一些有用的操作可能会很尴尬。要获得所有元素中的
val
,我们必须使用以下内容:

In [115]: np.frompyfunc(lambda obj: obj.val,1,1)(_105)                                   
Out[115]: 
array([[(0, 0), (0, 1), (0, 2), (0, 3)],
       [(1, 0), (1, 1), (1, 2), (1, 3)],
       [(2, 0), (2, 1), (2, 2), (2, 3)]], dtype=object)
或每个元组的第一个元素:

In [116]: np.frompyfunc(lambda obj: obj.val[0],1,1)(_105).astype(int)                    
Out[116]: 
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2]])

使用
numpy.full
将在每个“单元格”中生成一个具有相同对象的数组。对于数字之类的东西,这很好,因为数字
1
仍然是一个数字
1
。但是,由于您希望在每个单元格中具有不同的类对象,因此需要多次生成每个对象

现在,如果您使用的是自定义类,而不是整型或浮点型等数据类型,那么最好使用普通Python数组。这是因为numpy数组针对此类数据进行了优化。为此,请使用以下生成器

[[CustomClass('value') for j in range(size_x)] for i in range(size_y)]
如果您确实需要使用自定义类,您可能希望为该类内置一些数学函数。可以使用
\uuuuu add\uuuuu
类函数实现类似于加法的功能。这将允许将两个数组相加等操作正常进行,而不会引发类型错误。有关的详细信息。以下是一个示例

class CustomClass:
  def __init__(self, value):
    self.value = value

  def __add__(self, second):
    return self.value + second.value
使用此定义,下面的代码将添加这些对象的两个numpy数组。但是,这也适用于普通Python数组,因此使用numpy的唯一原因还是用于更大的数据操作,例如调整数组大小和点积乘法

array1 = [[CustomClass(i) for j in range(size_x)] for i in range(size_y)]
array2 = [[CustomClass(j*2) for j in range(size_x)] for i in range(size_y)]

array3 = array1 + array2
print(array3)

full
将相同的对象放在每个位置。您必须为每个元素调用对象创建者fresh,就像创建列表一样。您将第二个参数作为单个值提供,该值将重复。请尝试
np.fromfunction(lambda x,y:CustomClass('value'),(size_x,size_y))
为什么不使用列表?为什么在这里使用numpy?在这里使用numpy是没有意义的。几乎可以肯定的是,除非有一些我不知道的非常有趣的技巧,否则你不能做任何矢量化的事情。它将默认为
对象
类型,并且不如列表灵活。@juanpa.arrivillaga我想使用numpy对于一些性能/语法方面的优势。实际的应用程序是非常资源密集型的。我看不出
fromfunction
有什么帮助。看看
array1
。我认为它将是一个
CustomClass
和一个数组
class CustomClass:
  def __init__(self, value):
    self.value = value

  def __add__(self, second):
    return self.value + second.value
array1 = [[CustomClass(i) for j in range(size_x)] for i in range(size_y)]
array2 = [[CustomClass(j*2) for j in range(size_x)] for i in range(size_y)]

array3 = array1 + array2
print(array3)