gpt4 book ai didi

python - 使用 numpy 进行奇怪的索引

转载 作者:行者123 更新时间:2023-12-01 07:26:45 25 4
gpt4 key购买 nike

我有一个变量 x,形状为 (2,2,50,100)。

我还有一个数组 y,它等于 np.array([0,10,20])。当我索引 x[0,:,:,y] 时会发生一件奇怪的事情。

x = np.full((2,2,50,100),np.nan)
y = np.array([0,10,20])
print(x.shape)
(2,2,50,100)
print(x[:,:,:,y].shape)
(2,2,50,3)
print(x[0,:,:,:].shape)
(2,50,100)
print(x[0,:,:,y].shape)
(3,2,50)

为什么最后一个输出 (3,2,50) 而不是 (2,50,3)?

最佳答案

这就是 numpy 如何使用高级索引来广播数组形状。当您通过 0对于第一个索引,和 y对于最后一个索引,numpy 将广播 0y 的形状相同.以下等价成立:x[0,:,:,y] == x[(0, 0, 0),:,:,y] .这是一个例子

import numpy as np

x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])

np.equal(x[0,:,:,y], x[(0, 0, 0),:,:,y]).all()
# returns:
True

现在,因为您有效地传递了两组索引,所以您正在使用高级索引 API 来形成(在这种情况下)索引对。
x[(0, 0, 0),:,:,y])

# equivalent to
[
x[0,:,:,y[0]],
x[0,:,:,y[1]],
x[0,:,:,y[2]]
]

# equivalent to
rows = np.array([0, 0, 0])
cols = y
x[rows,:,:,cols]

# equivalent to
[
x[r,:,:,c] for r, c in zip(rows, columns)
]

其中第一个维度与 y 的长度相同.这就是你所看到的。

举个例子,看一个有 4 个维度的数组,它们在下一个块中描述:
x = np.arange(120).reshape(2,3,4,5)
y = np.array([0,2,4])

# x looks like:
array([[[[ 0, 1, 2, 3, 4], -+ =+
[ 5, 6, 7, 8, 9], Sheet1 |
[ 10, 11, 12, 13, 14], | |
[ 15, 16, 17, 18, 19]], -+ |
Workbook1
[[ 20, 21, 22, 23, 24], -+ |
[ 25, 26, 27, 28, 29], Sheet2 |
[ 30, 31, 32, 33, 34], | |
[ 35, 36, 37, 38, 39]], -+ |
|
[[ 40, 41, 42, 43, 44], -+ |
[ 45, 46, 47, 48, 49], Sheet3 |
[ 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]],

[[100, 101, 102, 103, 104],
[105, 106, 107, 108, 109],
[110, 111, 112, 113, 114],
[115, 116, 117, 118, 119]]]])
x有一个非常容易理解的顺序形式,我们现在可以用它来显示正在发生的事情......

第一个维度就像有 2 个 Excel 工作簿,第二个维度就像每个工作簿中有 3 个工作表,第三个维度就像每个工作表有 4 行,最后一个维度是每行(或每页列)5 个值。

这样看,求 x[0,:,:,0] ,是这样说的:“在第一个工作簿中,对于每张纸,对于每一行,给我第一个值/列。”
x[0,:,:,y[0]]
# returns:
array([[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]])

# this is in the same as the first element in:
x[(0,0,0),:,:,y]

但是现在有了高级索引,我们可以想到 x[(0,0,0),:,:,y]如“在第一个工作簿中,对于每张纸,对于每一行,给我 y th 值/列。好的,现在为 y 的每个值执行此操作”
x[(0,0,0),:,:,y]
# returns:
array([[[ 0, 5, 10, 15],
[20, 25, 30, 35],
[40, 45, 50, 55]],

[[ 2, 7, 12, 17],
[22, 27, 32, 37],
[42, 47, 52, 57]],

[[ 4, 9, 14, 19],
[24, 29, 34, 39],
[44, 49, 54, 59]]])

疯狂的地方是 numpy 将广播以匹配 索引数组的维度。因此,如果您想执行与上述相同的操作,但对于两个“Excel 工作簿”,则不必循环和连接。您可以将数组传递给第一个维度,但它是 必须有一个兼容的形状。

传递一个整数会被广播到 y.shape == (3,) .如果要将数组作为第一个索引传递,则只有数组的最后一个维度必须与 y.shape 兼容。 .即,第一个索引的最后一个维度必须是 3 或 1。

ix = np.array([[0], [1]])
x[ix,:,:,y].shape
# each row of ix is broadcast to length 3:
(2, 3, 3, 4)

ix = np.array([[0,0,0], [1,1,1]])
x[ix,:,:,y].shape
# this is identical to above:
(2, 3, 3, 4)

ix = np.array([[0], [1], [0], [1], [0]])
x[ix,:,:,y].shape
# ix is broadcast so each row of ix has 3 columns, the length of y
(5, 3, 3, 4)

在文档中找到了一个简短的解释: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing

编辑:

从最初的问题中,要获得所需切片的单行,您可以使用 x[0][:,:,y] :
x[0][:,:,y].shape
# returns
(2, 50, 3)

但是,如果您正在尝试 分配 对于这些子切片,您必须非常小心地查看原始数组的共享内存 View 。否则分配将不是原始数组,而是一个副本。

共享内存仅在您使用整数或切片对数组进行子集化时发生,即 x[:,0:3,:,:]x[0,:,:,1:-1] .

np.shares_memory(x, x[0])
# returns:
True

np.shares_memory(x, x[:,:,:,y])
# returns:
False

在您的原始问题和我的示例中 y既不是 int 也不是 slice,所以最终总是分配给原始副本。

但!因为你的数组 y可以表示为切片,你 CAN 实际上通过以下方式获得数组的可分配 View :

x[0,:,:,0:21:10].shape
# returns:
(2, 50, 3)

np.shares_memory(x, x[0,:,:,0:21:10])
# returns:
True

# actually assigns to the original array
x[0,:,:,0:21:10] = 100

这里我们使用切片 0:21:10抓取 range(0,21,10) 中的每个索引.我们必须使用 21而不是 20因为停止点被排除在切片之外,就像在 range 中一样功能。

所以基本上,如果您可以构建一个符合您的分割标准的切片,您就可以进行分配。

关于python - 使用 numpy 进行奇怪的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60422693/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com