使用索引替换二维 numpy 数组的一部分

Ara*_*D_B 5 python indexing numpy multidimensional-array

我试图将名为“S”的二维 numpy 数组的一部分替换为 i 和 j 的函数。给定 S:

>>> S
Out[1]: 
array([[ 1.,  0.,  0.],
      [ 0.,  3.,  0.],
      [ 0.,  0.,  9.]]
Run Code Online (Sandbox Code Playgroud)

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

>>> S[:, [i, j]][[i, j], :]
Out[2]: 
array([[ 1.,  0.],
      [ 0.,  3.]])
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试用另一个相同维度的数组 (tmp_arr) 替换数组 S 的相同元素时,python 没有给出错误,但它也没有做任何事情,这意味着 S 的元素保持不变并且不显示任何错误消息。

>>> tmp_arr
Out[3]: 
array([[ 555.,  0.],
       [ 0.,  555.]])

>>> S[:, [i, j]][[i, j], :] = tmp_arr
Run Code Online (Sandbox Code Playgroud)

我得到的是相同的矩阵:

>>> S
Out[4]: 
array([[ 1.,  0.,  0.],
      [ 0.,  3.,  0.],
      [ 0.,  0.,  9.]])
Run Code Online (Sandbox Code Playgroud)

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

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]
Run Code Online (Sandbox Code Playgroud)

我感谢您的意见和经验。

unu*_*tbu 4

您可以用来np.ix_构造所需的索引数组:

\n\n
In [91]: S[np.ix_([i,j],[i,j])]\nOut[91]: \narray([[1, 0],\n       [0, 3]])\n\nIn [92]: tmp_arr = np.eye(2)*555\n\nIn [93]: tmp_arr\nOut[93]: \narray([[ 555.,    0.],\n       [   0.,  555.]])\n\nIn [94]: S[np.ix_([i,j],[i,j])] = tmp_arr\n\nIn [95]: S\nOut[95]: \narray([[555,   0,   0],\n       [  0, 555,   0],\n       [  0,   0,   9]])\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

使用np.ix_适合对 进行赋值S,但请注意,有更快的方法来选择子数组:

\n\n
In [99]: %timeit S.take([i, j], axis=1).take([i, j], axis=0)\n100000 loops, best of 3: 3.32 \xc2\xb5s per loop\nIn [97]: %timeit S[:, [i, j]][[i, j], :]\n100000 loops, best of 3: 8.8 \xc2\xb5s per loop\nIn [96]: %timeit S[np.ix_([i,j],[i,j])]\n100000 loops, best of 3: 13 \xc2\xb5s per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

但与这些其他方法不同的是,S[np.ix_(...)] = ...它不使用链式索引,因此S.__setitem__会被调用并且赋值会影响S. 相反,S[:, [i, j]]返回 的子数组的副本S,因此分配给S[:, [i, j]][[i, j], :]仅影响子数组的此副本,而不影响S其本身。由于没有维护对此子数组副本的引用,因此 Python 在进行赋值后会丢弃该副本,因此赋值会丢失。这就是为什么链式索引不适合分配给S.

\n