说明
NumPy 教程 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
可以使用标准 Python x[obj]
语法对 ndarrays 进行索引和切片操作,其中 x 是数组,而 obj 是选择。 共有三种索引可用:字段访问,基本切片,高级索引,哪一个发生取决于 obj。
!!! note "说明"
在 Python, x[(exp1, exp2, ..., expN)]
相当于 x[exp1, exp2, ..., expN]
; 后者只是前者的句法糖。
基本切片(Basic slicing)将 Python 的基本概念扩展到 N 个维。 当 obj 是一个切片对象(由方括号内的 start:stop:step 表示法构造),整数或切片对象和整数的元组时,会产生切片操作。 省略号(Ellipsis)和 newaxis 对象也可以散布在这些对象上。
单元素索引的工作方式与其他标准 Python 序列的工作方式完全相同。它是基于 0 的,并接受从数组末尾开始索引的负索引。
x = np.arange(10)
x[2]
# 2
x[-2]
# 8
我们无需将每个维度的索引分离到它自己的一组方括号中,而是直接放在一起。
x.shape = (2, 5) # 现在x是二维的
x
'''
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
'''
x[1, 3]
# 8
x[1, -1]
# 9
如果对索引数少于维度的多维数组进行索引,则会得到一个子维度数组。例如:
x[0]
# array([0, 1, 2, 3, 4])
也就是说,每个指定的索引都会选择与其余选定维度对应的数组。在上面的示例中,选择 0 表示未指定长度为5的剩余维度,返回的是该维度和大小的数组。必须注意,返回的数组是一个视图(view),即它不是原始数组的副本,而是指向内存中与原始数组相同的值。在这种情况下,返回第一个位置(0)处的一维数组。因此,在返回的数组上使用单个索引会导致返回单个元素。即:
x[0][2]
# 2
因此请注意 x[0, 2] == x[0][2]
操作,尽管第二种情况效率更低,因为在随后由 2 索引的第一个索引之后创建了一个新的临时数组。
NumPy 使用 C 顺序索引。这意味着最后一个索引通常表示变化最快的内存位置,这与 Fortran 或 IDL 不同,前者表示内存中变化最快的位置。这种差异很可能会引起混淆。
基本切片将Python的切片基本概念扩展到N维。当obj是一个切片对象(由括号内的 start:stop:step 表示法构造)、一个整数、切片对象或者整数的元组时,就会发生基本切片操作。省略号和 newaxis 对象也可以与这些对象可以结合在一起。
使用 N 个整数进行索引的最简单情况是返回表示相应项的数组标量。与 Python 中的索引一样,所有索引都是基于零的。基本切片生成的所有阵列始终是原始阵列的视图。
NumPy 切片创建一个视图,而不是一个副本,就像内置 Python 序列(如字符串、元组和列表)一样。在从大数组中提取一小部分时必须小心,因为提取的小部分包含对大原始数组的引用,在所有从该数组派生的数组都被垃圾回收之前,不会释放其内存。在这种情况下,建议使用显式 copy()。
副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。
序列切片的标准规则适用于基于每个维度的基本切片(包括使用 step 索引)。要记住的一些有用概念和规则,包括:
1)基本的切片语法是 i:j:k,其中 i 是起始索引,j 是停止索引,k是步骤:
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[1:7:2]
# array([1, 3, 5])
2)负 i 和 j 被解释为 n+i 和 n+j,其中 n 是相应维度中的元素数。负k使步进指数变小。根据上述示例:
x[-2:10]
# array([8, 9])
x[-3:3:-1]
# array([7, 6, 5, 4])
3)假设n是要切片的维度中的元素数。然后,如果没有给i,k>0 时默认为0,k<0
时默认为 n-1。如果未给定j,则k>0时默认为n,k<0
时默认为-n-1。如果未指定k,则默认为1。注意 ::
与 :
相同,表示选择沿该轴的所有索引。根据上述示例:
x[5:]
# array([5, 6, 7, 8, 9])
4)如果选择元组中的对象数小于 N,则 :
假定后继的任意维。例如:
x = np.array([[[1],[2],[3]], [[4],[5],[6]]])
x.shape
# (2, 3, 1)
x[1:2]
'''
array([[[4],
[5],
[6]]])
'''
5)整数i返回与i相同的值:i+1,但返回对象的维数减少了1。特别是,第p个元素为整数(以及所有其他 :
)的选择元组返回维度为N-1的对应子数组。如果N=1,则返回的对象是数组标量。这些对象用标量来解释。
6)如果选择元组包含所有条目:除了第p个条目,第p个条目是切片对象i:j:k,则返回的数组具有维数N,该维数N是由元素i,i+k,…,i+(m-1)k<j
的整数索引返回的子数组串联而成。
7)在切片元组中使用多个non:
项进行基本切片,就像使用单个non:
项重复应用切片一样,其中non:项被依次获取(所有其他non-:项被替换为:
)。因此,在基本切片下,x[ind1,…,ind2,:]
的行为类似于x[ind1][…,ind2,:]。(对于高级索引,上述情况并非如此。)
8)可以使用切片来设置数组中的值,但(与列表不同)永远无法增加数组。要在 x[obj] = value 中设置的值的大小值必须(可广播)为与 x[obj] 相同的形状。
9)切片元组始终可以构造为obj,并在 x[obj] 表示法中使用。可以在构造中使用切片对象来代替 [start:stop:step] 符号。例如,x[1:10:5, ::-1] 也可以实现为 obj = (slice(1, 10, 5), slice(None, None, -1)); x[obj]
。这对于构造在任意维数组上工作的通用代码非常有用。
有一些工具可以方便地将数组形状与表达式和指定中的数组形状进行轻松匹配。
省略号(Ellipsis,字面值 ...
)扩展为选择元组索引所有维度所需的多个 :
。在大多数情况下,这意味着扩展的选择元组的长度为 x.ndim。可能只存在一个省略号。根据上述示例:
x = np.array([[[1],[2],[3]], [[4],[5],[6]]])
x
'''
array([[[1],
[2],
[3]],
[[4],
[5],
[6]]])
'''
x.ndim
# 3
x[..., 0]
'''
array([[1, 2, 3],
[4, 5, 6]])
'''
相当于:
x[:, :, 0]
'''
array([[1, 2, 3],
[4, 5, 6]])
'''
选择元组中的每个 newaxis (一个 Numpy 的常量)对象用于将结果选择的维度扩展一个单位长度维度。添加的维度是 newaxis 对象在选择元组中的位置。newaxis 是 None 的别名,可以使用 None 替代,并获得相同的结果。根据上述示例:
x[:, np.newaxis, :, :].shape
# (2, 1, 3, 1)
x[:, None, :, :].shape
# (2, 1, 3, 1)
这可以方便地以一种需要显式重塑操作的方式组合两个阵列。例如:
x = np.arange(5)
x[:, np.newaxis] + x[np.newaxis, :]
'''
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
'''
更新时间:June 9, 2022, 6:09 p.m. 标签:numpy array 索引