同时为Numpy数组的特定行和列赋值

k4ymrczo  于 2023-03-23  发布在  其他
关注(0)|答案(2)|浏览(174)

下面代码的预期输出:

array([[ 0,  1,  2,  3],
       [ 4,  999,  999,  7],
       [ 8,  999, 999, 11],
       [12, 13, 14, 15]])

代码:

import numpy as np
A = np.array(range(16)).reshape((4,4))
A[[1,3],:][:, [1,3]] = [[999,999],[999,999]]
print(A)

但是,这些值没有改变。

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

我应该怎么做才能得到所需的输出?我不允许使用循环来手动分配每个值。

**更新:**场景二:如果我想要A[[1,3],[1,3]] = inner,它会抛出异常形状不匹配:shape(2,2)的值数组无法广播到shape(2,)的索引结果。我该怎么办?

场景2的期望输出:

array([[ 0,  1,  2,  3],
      [ 4,  999,  6,  999],
      [ 8,  9, 10, 11],
      [12, 999, 14, 999]])
balp4ylt

balp4ylt1#

具体解决方案

您可以执行以下操作以获得所需的结果:

import numpy as np
A = np.array(range(16)).reshape((4,4))

inner = np.array([[999,999],[999,999]])

border = 1
A[border:border + inner.shape[0],
    border:border + inner.shape[1]] = inner
  • 为了清楚起见,单独定义内部数组。
  • border的作用是定义你离边界有多远。
  • A的输出为:
array([[  0,   1,   2,   3],
       [  4, 999, 999,   7],
       [  8, 999, 999,  11],
       [ 12,  13,  14,  15]])

广义二维解

在上面的例子中,内部数组和外部数组在两个方向上的距离都是相同的,但是你可以定义和调整两个border参数来推广解决方案。例如,如果原始数组较大(10x10),你想在它的任意位置嵌入一个(3x3)数组,你可以做以下事情:

import numpy as np
A = np.array(range(100)).reshape((10,10))

inner = np.array([[999,999,999],[999,999,999],[999,999,999]])

border_1 = 1
border_2 = 4
A[border_1:border_1 + inner.shape[0],
    border_2:border_2 + inner.shape[1]] = inner

A的输出是:

array([[  0,   1,   2,   3,   4,   5,   6,   7,   8,   9],
       [ 10,  11,  12,  13, 999, 999, 999,  17,  18,  19],
       [ 20,  21,  22,  23, 999, 999, 999,  27,  28,  29],
       [ 30,  31,  32,  33, 999, 999, 999,  37,  38,  39],
       [ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49],
       [ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59],
       [ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69],
       [ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79],
       [ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89],
       [ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99]])

额外提示

您可以利用np.full,而不是手动写入999的数组。

np.full((3, 3), 999)

产生...

array([[999, 999, 999],
       [999, 999, 999],
       [999, 999, 999]])

这可以使写入内部数组快得多。

fquxozlt

fquxozlt2#

我将尝试演示如何索引数组的块。

In [52]: arr = np.arange(16).reshape(4,4);arr
Out[52]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

使用2个列表(大小相同)进行索引,选择“对角线”:

In [53]: arr[[1,3],[1,3]]
Out[53]: array([ 5, 15])

实际上,这是选择arr[1,1]arr[3,3],从每个列表中配对一个值。您不能将(2,2)块分配给(2,)形状。
您选择了具有双重索引的块:

In [54]: arr[[1,3],:][:,[1,3]]
Out[54]: 
array([[ 5,  7],
       [13, 15]])

第一次索引返回一个副本,所以进一步尝试赋值将修改该副本,而不是原始数组。
在评论中,我建议使用两个列表进行索引:

In [55]: arr[[[1],[3]],[1,3]]
Out[55]: 
array([[ 5,  7],
       [13, 15]])

更一般地说,我们使用一个helper函数将两个1d列表转换为broadcast的数组:

In [56]: np.ix_([1,3],[1,3])
Out[56]: 
(array([[1],
        [3]]),
 array([[1, 3]]))

该数组元组可以选择我们的块,并可用于设置:

In [57]: arr[_]
Out[57]: 
array([[ 5,  7],
       [13, 15]])

你可能想回顾一下broadcasting的概念。它在索引时和在做数学时一样重要。同样的规则适用,例如在[56]中添加两个数组:

In [58]: Out[56][0]+Out[56][1]
Out[58]: 
array([[2, 4],
       [4, 6]])

对于这对索引列表,我们可以使用切片来选择相同的块:

In [59]: arr[1::2, 1::2]
Out[59]: 
array([[ 5,  7],
       [13, 15]])

[59]是一个basic索引的例子,而所有其他的都是advanced索引。
最后,演示作业:

In [60]: arr[[[1],[3]],[1,3]] = [[100,110],[120,130]]
In [61]: arr
Out[61]: 
array([[  0,   1,   2,   3],
       [  4, 100,   6, 110],
       [  8,   9,  10,  11],
       [ 12, 120,  14, 130]])

In [62]: arr[1::2, 1::2] = -1
In [63]: arr
Out[63]: 
array([[ 0,  1,  2,  3],
       [ 4, -1,  6, -1],
       [ 8,  9, 10, 11],
       [12, -1, 14, -1]])

相关问题