首页 > 解决方案 > 如何在数组(numpy)中制作“可变”数字?

问题描述

我正在尝试创建一个数组,其中多次包含相同的数字,但如果我在任何地方更改它,它应该在任何地方都更改。与列表一样:

a = b = [1]
>>> a.append(1)
>>> print(b)
>>> [1, 1]

所以我想要一个这样的数组:

number = 10   
arr = numpy.zeros((10, 10))
arr[0][0] = number
arr[1][1] = number
arr[0][0] += 1
print(arr[1][1])

在这里它应该输出“11”。那么有没有办法对一个数字进行多次引用?我知道你可以用 11 替换所有的 10,但首先这效率太低,其次这可能会搞砸,因为另一个数字也可能巧合为 10。

谢谢。

标签: arraysnumpyreference

解决方案


零维 numpy 数组在许多方面表现得像一个可变数字:

>>> import numpy as np                                                  
>>>                                                                                                                 
>>> a = 2.0            # ordinary immutable number
>>> am = np.array(2.0) # "mutable number"                                                                                          
>>>                                                                                                                 
>>> A = np.array([[a, a, am, a], [am, am, a, a]], dtype=object)
>>> A
array([[2.0, 2.0, array(2.), 2.0],                                                                                  
       [array(2.), array(2.), 2.0, 2.0]], dtype=object)

这有点难看,所以下面我将在打印之前转换为浮点数:

>>> A.astype(float)                                                          
array([[2., 2., 2., 2.],                                                                                            
       [2., 2., 2., 2.]])

这两个不都是相等的,左上角是不可变的

>>> A[0, 0] += 1

分配给它的只有直接寻址的单元格会受到影响:

>>> A.astype(float)
array([[3., 2., 2., 2.],
       [2., 2., 2., 2.]])
>>> a
2.0

第三个是可变的

>>> A[0, 2] -= 1

分配给它的所有引用都会受到影响:

>>> A.astype(float)
array([[3., 2., 1., 2.],
       [1., 1., 2., 2.]])
>>> am
array(1.)

直接赋值需要[()]语法:

>>> A[0, 2][()] = 1.5
>>> am
array(1.5)

否则链接会断开:

>>> A[0, 2] = 1.8
>>> A.astype(float)
array([[3. , 2. , 1.8, 2. ],
       [1.5, 1.5, 2. , 2. ]])

更新:

在评论中,OP 指定了以下所需的行为:

如果可变数在 中am出现k次数A,那么在A * 3可变数中应该乘以3**k,而不是3

我们可以使用 inplace ( *=) 运算符和一些技巧来获得这种行为;如果我们想保留原件A,我们必须先制作一个副本:

因为numpys 复制机器将我们的 0D 数组标准化,所以需要更多技巧来制作好的副本:

>>> import copy
>>>
>>> B = np.empty_like(A)
>>> B.ravel()[...] = copy.deepcopy((*A.ravel(),))

现在对副本进行就地乘法:

>>> import operator as op
>>> 
>>> C = np.frompyfunc(op.imul, 2, 1)(B, 3)
>>> 
>>> A
array([[2.0, 2.0, array(2.), 2.0],
       [array(2.), array(2.), 2.0, 2.0]], dtype=object)
>>> C
array([[6.0, 6.0, array(54.), 6.0],
       [array(54.), array(54.), 6.0, 6.0]], dtype=object)

注意B最后会包含一些无用的混合数据,应该丢弃。

>>> B
array([[2.0, 2.0, array(54.), 2.0],
       [array(54.), array(54.), 2.0, 2.0]], dtype=object)
>>> del B

最后一点:这比理智的编程更狡猾,所以请把它看作是可以做的,而不是应该做的。


推荐阅读