使用索引更换2D numpy数组的一部分

7

我将尝试替换名为"S"的2D numpy数组的一部分,该部分是i和j的函数。给定S如下:

>>> S
Out[1]: 
array([[ 1.,  0.,  0.],
      [ 0.,  3.,  0.],
      [ 0.,  0.,  9.]]

对于i=0和j=1,可以使用以下语法访问行i和j以及列i和j的元素:

>>> S[:, [i, j]][[i, j], :]
Out[2]: 
array([[ 1.,  0.],
      [ 0.,  3.]])

现在,当我尝试用另一个相同维度的数组(tmp_arr)替换数组S的相同元素时,Python不会报错,但也不会执行任何操作,这意味着S的元素保持不变,也没有显示错误消息。
>>> tmp_arr
Out[3]: 
array([[ 555.,  0.],
       [ 0.,  555.]])

>>> S[:, [i, j]][[i, j], :] = tmp_arr

而我得到的是相同的矩阵:

>>> S
Out[4]: 
array([[ 1.,  0.,  0.],
      [ 0.,  3.,  0.],
      [ 0.,  0.,  9.]])

显然,以下方法可以实现,但我正在寻找一种优雅的解决方案:

S[i, i] = tmp_arr[0, 0]
S[i, j] = tmp_arr[0, 1]
S[j, i] = tmp_arr[1, 0]
S[j, j] = tmp_arr[1, 1]

我感谢您的评论和经验。

2个回答

4
你可以使用 np.ix_ 来构建所需的索引数组:
In [91]: S[np.ix_([i,j],[i,j])]
Out[91]: 
array([[1, 0],
       [0, 3]])

In [92]: tmp_arr = np.eye(2)*555

In [93]: tmp_arr
Out[93]: 
array([[ 555.,    0.],
       [   0.,  555.]])

In [94]: S[np.ix_([i,j],[i,j])] = tmp_arr

In [95]: S
Out[95]: 
array([[555,   0,   0],
       [  0, 555,   0],
       [  0,   0,   9]])

使用 np.ix_ 对于给 S 赋值很好,但请注意有更快的选择子数组的方法:

In [99]: %timeit S.take([i, j], axis=1).take([i, j], axis=0)
100000 loops, best of 3: 3.32 µs per loop
In [97]: %timeit S[:, [i, j]][[i, j], :]
100000 loops, best of 3: 8.8 µs per loop
In [96]: %timeit S[np.ix_([i,j],[i,j])]
100000 loops, best of 3: 13 µs per loop

但与这些其他方法不同,S[np.ix_(...)] = ... 不使用链式索引(chained indexing),因此 S.__setitem__ 被调用并且赋值影响了 S。相比之下,S[:, [i, j]] 返回的是子数组(subarray)的副本(copy),因此对 S[:, [i, j]][[i, j], :] 进行赋值只会影响到这个子数组的副本,而不是 S 本身。由于没有对这个子数组的副本进行引用,Python 在赋值完成后将其丢弃,所以赋值被丢失。这就是为什么链式索引不能用于对 S 赋值的原因。


感谢@unutbu的回答。这绝对是有道理的。 - Arash_D_B

0
>>> a
array([[ 1.,  0.,  0.],
       [ 0.,  3.,  0.],
       [ 0.,  0.,  9.]])
>>> i, j = 0 , 1
>>> a[i:j+1,i:j+1] = np.arange(100, 104).reshape(2,2)
>>> a
array([[ 100.,  101.,    0.],
       [ 102.,  103.,    0.],
       [   0.,    0.,    9.]])
>>> 

为确保他只获取他想要的4个项目,您必须执行 a[i:j+1:j-i, i:j+1:j-i],不是吗?当然,一定要确保 j > i - Jaime
请注意,i和j可以是非连续的。例如,i=0且j=2。换句话说,如果我替换S[0,0]、S[0,2]、S[2,0]和S[2,2],那么我认为上述解决方案将不起作用。如果我错了,请纠正我。 - Arash_D_B
@Arian,你说得对 - 我的解决方案将替换一个连续的范围。不幸的是,这不是我的第一次误解。 - wwii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接