为numpy数组赋值的花式索引

fgr*_*egg 4 python arrays numpy

我有一个2维numpy数组:

A = np.zeros(16).reshape(4,4)
Run Code Online (Sandbox Code Playgroud)

我希望(1, 1), (1,3), (3,1),并且(3,3)单元格的值为1.

A[[1,3], [1:3]] = 1 
Run Code Online (Sandbox Code Playgroud)

只分配1 (1,1)(3,3).

A[[1,3], :][:, [1, 3]] = 1
Run Code Online (Sandbox Code Playgroud)

不起作用,因为它使数据的副本不是视图.这样做的正确方法是什么?

shx*_*hx2 5

使用步骤= 2的切片:

A[1::2,1::2] = 1
Run Code Online (Sandbox Code Playgroud)

或者明确地传递所有索引:

A[[1,1,3,3],[1,3,1,3]] = 1
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是,有一种方法可以用广播来实现你的第二个例子.`a [[[1],[3]],[[1,3]]]`.我认为这可能是OP最初的目标. (2认同)

sen*_*rle 4

通常,当您使用数组以这种方式索引另一个数组时,numpy期望每个数组RC等具有相同的形状。例如,假设您想从此数组中提取非零值:

>>> a
array([[1, 3, 0, 0],
       [0, 0, 0, 0],
       [2, 4, 0, 0],
       [0, 0, 0, 0]])
Run Code Online (Sandbox Code Playgroud)

您将创建一个行索引数组R

>>> R
array([[0, 2],
       [0, 2]])
Run Code Online (Sandbox Code Playgroud)

和一个列索引数组C

>>> C
array([[0, 0],
       [1, 1]])
Run Code Online (Sandbox Code Playgroud)

并像这样传递它们:

>>> a[R, C]
array([[1, 2],
       [3, 4]])
Run Code Online (Sandbox Code Playgroud)

请注意,它们可以是您喜欢的任何形状——输出将采用相同的形状:

>>> RR
array([0, 2, 0, 2])
>>> CC
array([0, 0, 1, 1])
>>> a[RR, CC]
array([1, 2, 3, 4])
Run Code Online (Sandbox Code Playgroud)

但是,如果您的索引数组中有重复项,那么您可以通过使用广播来省去一些麻烦。唯一的问题是结果数组必须能够广播。这意味着您需要明确地赋予它们额外的维度。我将使用切片语法来保留额外的维度。

>>> r = R[0:1,:]
>>> c = C[:,0:1]
>>> r
array([[0, 2]])
>>> c
array([[0],
       [1]])
>>> a[r, c]
array([[1, 2],
       [3, 4]])
Run Code Online (Sandbox Code Playgroud)

如果你没有明确地给他们额外的维度,numpy尽最大努力理解你所传递的内容,但它并不总是按预期工作。将0:1切片替换为0删除额外的维度:

>>> rr = r[0,:]
>>> cc = c[:,0]
>>> rr
array([0, 2])
>>> cc
array([0, 1])
>>> a[rr, c]
array([[1, 2],
       [3, 4]])
>>> a[r, cc]
array([[1, 4]])
>>> a[rr, cc]
array([1, 4])
Run Code Online (Sandbox Code Playgroud)

第一个 ( a[rr, c]) 之所以有效,是因为numpy可以从它的形状看出c它应该广播。但另外两个是不明确的,因此numpy假设您并不打算广播它们。

但是,请注意,这numpy也提供了使平面数组可广播的快捷方式。这可以派上用场!

>>> a[numpy.ix_(rr, cc)]
array([[1, 3],
       [2, 4]])
Run Code Online (Sandbox Code Playgroud)