Python: 切片多维数组

67

我知道如何切片一维序列: arr[start:end],并访问数组中的元素: el = arr[row][col]

现在,我正在尝试类似于slice = arr[0:2][0:2](其中arr是一个numpy数组),但它没有给我前两行和前两列,而是重复了前两行。我刚刚做了什么,如何沿另一个维度切片?


arr 是什么数据类型?它是一个列表的列表吗? - mgilson
@mgilson 我在问题中更新了类型。 - SlightlyCuban
2个回答

97

如果您使用numpy,那么这很容易:

slice = arr[:2,:2]

或者如果你需要0值,

slice = arr[0:2,0:2]

你会得到相同的结果。

*请注意,slice实际上是一个内置类型的名称。通常,我建议给你的对象取一个不同的“名称”。


另一种方法,如果你正在使用列表的列表*:

slice = [arr[i][0:2] for i in range(0,2)]

(注意这里的0是不必要的:[arr[i][:2] for i in range(2)]也可以工作。)

我在这里做的是逐行获取每个所需的行(arr[i])。然后,我从该行中切取我想要的列,并将其添加到我正在构建的列表中。

如果你尝试这样:arr[0:2],你会得到前两行,如果你再次切片arr[0:2][0:2],你只是再次切割了前两行。

*这对于NumPy数组实际上也有效,但与我上面发布的“本地”解决方案相比,速度会较慢。


那么,arr[0:2][0:2]arr[row][col]相比实际上是做什么的? - SlightlyCuban
2
@mgilson 我尝试了这个方法,得到了一些奇怪的结果。假设我有a = [[1,2,3],[4,5,6],[7,8,9]],然后 a[0][:]=[1, 2, 3],但很奇怪的是 a[:][0] 仍然是 [1,2,3]。我认为应该是 [1,4,7]。如果您能告诉我这里错在哪里,我将不胜感激。 - Alexander Cska
4
@AlexanderCska 其实那并不奇怪。这两个表达式基本上是“取出a的第一个元素并返回其副本”和“复制a并返回副本的第一个元素”。解决方法是[x[0] for x in a],或者如果你在使用numpy,就是a[:, 0] - mgilson
1
@mgilson 好的,我试图将FORTRAN符号应用到Python上,现在我看到事情有点更加复杂了。 - Alexander Cska
如果你正在使用 numpy,它们实际上非常相似... 如果没有numpy,就会非常不同(在多维数组中更像C语言中的“指向数组的指针数组”)。 - mgilson
1
@mgilson 我现在明白了,在正常情况下,a[:]是一个副本,并用于避免多个指针引用相同的内存位置。我只是混淆了C和Python语法。 - Alexander Cska

0

对于多维数组的切片,必须指定维度(即轴)。正如 OP 所指出的那样,arr[i:j][i:j]arr[i:j] 是完全相同的,因为 arr[i:j] 沿着第一维(行)进行了切片,并且与 arr 具有相同数量的维度(您可以通过 arr[i:j].ndim == arr.ndim 进行确认);因此,第二个切片仍然沿着第一维进行切片(这已经被第一个切片完成了)。要沿着第二个维度进行切片,必须显式指定,例如:

arr[:2][:, :2]                   # its output is the same as `arr[:2, :2]`

: 表示在该轴上切片所有元素,因此在上述代码中第二个轴上有一个隐式的 :(即 arr[:2, :][:, :2])。上述代码所做的是从结果数组中切取前两行(或第一轴上的前两个数组),然后再从中切取前两列(或第二轴上的前两个数组)。

可以使用 ... 代替多个冒号(:),因此对于一般的 n 维数组,以下代码产生相同的输出:

w = arr[i:j, m:n]
x = arr[i:j, m:n, ...]
y = arr[i:j][:, m:n]
z = arr[i:j, ...][:, m:n, ...]

话虽如此,arr[:2, :2]是规范的方式,因为在arr[i:j][:, i:j]的情况下,arr[i:j]创建了一个临时数组,该数组由[:, i:j]索引,因此效率相对较低。

然而,在某些情况下,链式索引是有意义(或可读性更好),例如,如果您想使用索引列表来索引多维数组。例如,如果您想使用索引列表来切片4x4数组的左上角,则链式索引会给出正确的结果,而单个索引会给出不同的结果(这是由于numpy高级索引),其中值对应于索引列表中每个位置的索引对。

arr = np.arange(1,17).reshape(4,4)
rows = cols = [0,1]
arr[rows][:, cols]               # <--- correct output
arr[rows, cols]                  # <--- wrong output
arr[[[e] for e in rows], cols]   # <--- correct output
arr[np.ix_(rows, cols)]          # <--- correct output

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