为什么替换 numpy 数组中的值并不总是有效

Why replacing values in numpy array does not always work

我正在尝试使用以下命令 replace/overwrite 数组中的值:

import numpy as np
test = np.array([[4,5,0],[0,0,0],[0,0,6]])
test
Out[20]:
array([[4., 5., 0.],
       [0., 0., 0.],
       [0., 0., 6.]])

test[np.where(test[...,0] != 0)][...,1:3] = np.array([[10,11]])
test
Out[22]:
array([[4., 5., 0.],
       [0., 0., 0.],
       [0., 0., 6.]])

但是,在Out22中可以看到,数组test并没有被修改。所以我得出结论,不可能简单地覆盖数组的一部分或几个单元格。

然而,在其他情况下,可以覆盖数组的几个单元格。例如,在下面的代码中:

test = np.array([[1,2,0],[0,0,0],[0,0,3]])
test
Out[11]:
array([[1., 2., 0.],
       [0., 0., 0.],
       [0., 0., 3.]])

test[test>0]
Out[12]:
array([1., 2., 3.])

test[test>0] = np.array([4,5,6])
test
Out[14]:
array([[4., 5., 0.],
       [0., 0., 0.],
       [0., 0., 6.]])

因此,我的 2 个问题:

1- 为什么第一个命令

test[np.where(test[...,0] != 0)][...,1:3] = np.array([10,11])

不允许修改数组测试?为什么它不允许访问数组单元格并覆盖它们?

2- 考虑到我的代码需要使用上面的命令 select 单元格,我怎样才能让它工作?

非常感谢!

我给你做一个。 有效:

test[...,1:3][np.where(test[...,0] != 0)] = np.array([[10,11]])

array([[ 4, 10, 11],
       [ 0,  0,  0],
       [ 0,  0,  6]])

为什么?它是两个因素的组合 - numpy 索引和 .__setitem__ 调用。

python 解释器向后读取行。当它到达 = 时,它会尝试在最左边的事物上调用 .__setitem____setitem__ 是(希望)对象的一种方法,并且有两个输入,目标和索引(在它之前 [...] 之间的任何内容)。

a[b] = c  #is intepreted as
a.__setitem__(b, c)

现在,当我们在 numpy 中建立索引时,我们可以使用三种基本方法。

  • 切片(returns 次观看)
  • 'advanced indexing'(returns份)
  • 'simple indexing'(也returns份)

“高级”和“简单”索引之间的一个主要区别是 numpy 数组的 __setitem__ 函数可以解释高级索引。而 views 表示数据地址相同,所以我们不需要 __setitem__ 来访问它们。

所以:

test[np.where(test[...,0] != 0)][...,1:3] = np.array([[10,11]])  #is intepreted as

(test[np.where(test[...,0] != 0)]).__setitem__( slice([...,1:3]), 
                                                np.array([[10,11]]))

但是,由于 np.where(test[...,0] != 0) 是一个 advanced index(test[np.where(test[...,0] != 0)]) returns 一个副本,然后丢失,因为它从未被分配。它确实获取了我们想要的元素并将它们设置为 [10,11],但结果丢失在缓冲区中的某个地方。

如果我们这样做:

test[..., 1:3][np.where(test[..., 0] != 0)] = np.array([[10, 11]]) #is intepreted as

(test[..., 1:3]).__setitem__( np.where(test[...,0] != 0), np.array([[10,11]]) )

test[...,1:3]是一个view,所以还是指向同一个内存。现在 setitemtest[...,1:3] 中查找对应 np.where(test[...,0] != 0) 的位置,并将它们设置为等于 np.array([[10,11]])。一切正常。

您也可以这样做:

test[np.where(test[...,0] != 0), 1:3] = np.array([10, 11])

现在,由于所有索引都在一组括号中,它会在这些索引上调用 test.__setitem__,这也会正确设置数据。

更简单的(也是最 pythonic 的)是:

test[test[...,0] != 0, 1:3] = np.array([10,11])