跳至主要內容

NumPy索引和切片

Akkiri...大约 7 分钟数据分析机器学习PythonPython

什么是索引、切片?

简单来说,数组中的某个元素可以通过索引来访问。切片指的是从数组中提取“子数组”的操作。

需要注意的是,NumPy 的索引和切片都是基于 0 开始的。此外,NumPy 的切片操作返回的是原数组的视图 (view) 而不是副本 (copy),因此对切片操作所得到的数组进行修改会直接影响到原数组。后续将专门讲解视图和副本之间的区别。

一维数组索引、切片

一维数组可以使用索引来访问和操作数组中的某个元素。一维数组的索引从 0 开始,想要取出数组 a 的第一个元素,可以用 a[0] 或 a[-11]。a[-1] 或 a[10] 则取出数组 a 的最后一个元素。

行向量、列向量

行向量、列向量都被一般视作特殊的二维数组。也就是说,行向量是一行多列矩阵,而列向量是多行一列矩阵。

在 NumPy 中,numpy.newaxis 是一个特殊的索引,用于增加数组的维度。它的作用是在数组的某个位置添加一个新轴,从而改变数组的维度。

具体来说,使用 numpy.newaxis 将会在数组的一个指定位置添加一个新的维度。对于一个一维数组 arr,我们可以使用 arr[:, numpy.newaxis] 将其转换为一个二维数组,其中新的维度被添加在列的方向上。这个操作将会把数组变成一个列向量。arr[numpy.newaxis, :] 则把一维数组变成行向量。

相反地,在 NumPy 中,numpy.squeeze() 函数用于从数组的形状中删除单维度的条目。这意味着它可以去掉数组中的长度为 1 的维度,并返回一个新的数组,其维度数目更少。

numpy.squeeze() 函数可以帮助我们简化数组的形状,使其更符合我们的需求。在某些情况下,例如在机器学习模型的输入中,我们需要使用具有特定形状的数组,而 numpy.squeeze() 可以帮助我们将数据变形为所需的形状。

切片

切片访问一维数组中的“子数组”,即多个元素。切片是一个包含开始索引和结束索引的范围,用冒号分隔。开始索引指定要获取的第一个元素的位置,结束索引指定要获取的最后一个元素的位置+1。

下面是使用例:

arr = np.arange(-5, 5+1)
# [-5 -4 -3 -2 -1  0  1  2  3  4  5]

# 一维数组连续切片
arr[0:3]
arr[:3]
arr[[0, 1, 2]]
# [-5, -4, -3]

# 一维数组以固定步长切片,步长为 2
arr[1::2]
# [-4, -2,  0,  2,  4]

# 一维数组倒序
arr[::-1]
# [ 5,  4,  3,  2,  1,  0, -1, -2, -3, -4, -5]

整数索引、切片

使用整数索引,大家可以传递一个整数来访问数组的单个元素,或者传递一个整数数组来访问数组的多个元素。

如果传递一个整数数组,则该数组的每个元素将被视为索引,从而返回一个新的数组,该数组包含原始数组中相应索引处的元素。如下例,整数索引为数组 [0, 1, 2, -1],我们提取一维数组的第 1、2、3 和最后一个 (-1) 元素,结果还是一维数组。

arr = np.arange(-5, 5+1)

arr[[0, 1, 2, -1]]
# [-5, -4, -3, 5]

同时,我们可以用 np.r_[0:3, -1] 构造一个数组,也能提取相同的元素组合。numpy.r_() 是一个用于将切片对象转换为一个沿着第一个轴堆叠的 NumPy 数组的函数。它可以在数组创建和索引时使用。

arr = np.arange(-5, 5+1)

np.r_[0:3, 5:7]
# [0, 1, 2, 5, 6]

arr[np.r_[0:3, -1]]
# [-5, -4, -3, 5]

布尔索引、切片

布尔索引 (Boolean indexing) 是一种使用布尔值来选择数组中的元素的技术。在使用布尔索引时,可以通过一些条件来生成一个布尔数组,该布尔数组与要索引的数组具有相同的形状,然后使用该布尔数组来选择要访问的数组元素。下例为利用布尔值切片我们分别提取数组中大于1、小于 0 的元素。

arr = np.arange(-5, 5+1)

arr[arr > 1]
# [2, 3, 4, 5]

arr[arr < 0]
# [-5, -4, -3, -2, -1]

视图 VS 副本

在 NumPy 中,有两种不同的方式来创建新的数组对象:视图 (view) 和副本 (copy)。

视图是原始数组的一个新视图,一种重新排列、重新解释。视图是原始数组共享相同的数据,不会创建新的内存。换句话说,视图是原始数组的一个不同的“窗口”,它可以访问原始数组的相同数据块。当对视图进行更改时,原始数组也会发生相应的更改。

副本则是原始数组的一份完整的拷贝,修改副本不会影响原始数组。当对数组进行切片或使用 numpy.copy() 方法时,将生成一个副本。副本的创建可以使用 numpy.copy() 方法或者 numpy.array() 函数的参数 copy = True 来实现。

本节之前的各种索引、切片方法实际上创建的都只是原数组的视图,改变这些视图就会原数组,并“牵一发动全身”地改变所有视图。而 numpy.copy() 则创建了全新的内存,即副本。

下面是使用例:

# 创建一个一维数组
a = np.array([1, 2, 3, 4, 5])

# 创建一个切片视图
s = a[1:3]

# 修改视图中的数据
s[0] = 1000

# 查看原始数组
print(a) # 输出:[1 1000 3 4 5]

# 创建一个整数数组索引副本
c = a[[1, 3]].copy()

# 修改副本中的数据
c[0] = 888

# 查看原始数组
print(a) # 输出:[1 1000 3 4 5]
print(c) # 输出:[888 4]

二维数组索引、切片

取出单一元素

要取出二维 NumPy 数组中特定索引的元,可以使用索引操作符 [] 来访问。可以将需要访问的元素的行索引和列索引作为参数传递给这个操作符。下例为从二维数组 a 中取出单一元素,a[0, 0] 代表第 0 行、第 0 列。请大家特别注意 a[[1], [2]] 的结果为一维数组。

import numpy as np

arr = np.arange(-7, 7+1).reshape(3, 5)
# [[-7, -6, -5, -4, -3],
#  [-2, -1,  0,  1,  2],
#  [ 3,  4,  5,  6,  7]]

# 取出单一元素
arr[1, 2]
arr[1][2]
# 0

# 取出一维数组
arr[[1], [2]]
# array([0])

取出行

要取出二维 NumPy 数组中特定行的元素,也是使用索引操作符 [] 来访问。你可以将需要访问的行的索引作为第一个参数传递给这个操作符,用冒号 : 表示需要访问的列范围。 图 10 所示,取出第 0 行,只需 a[0],结果为一维数组。而 a[[0], :] 取出第 0 行,结果为二维数组。

import numpy as np

arr = np.arange(-7, 7+1).reshape(3, 5)

# 取出行(一维数组)
arr[0]
arr[0, :]
# [-7, -6, -5, -4, -3]

# 取出行(二维数组)
arr[[0], :]
arr[0, np.newaxis]
# [[-7, -6, -5, -4, -3]]

# 取出多行
arr[[0, 2]]
arr[[0, 2], :]
# [[-7, -6, -5, -4, -3],
#  [ 3,  4,  5,  6,  7]]

取出列

与取出行的操作类似,我们也可以取出特定列。

import numpy as np

np.arange(-7, 7+1).reshape(3, 5)

# 取出列(一维数组)
arr[:, 0]
arr[..., 0]
# [-7, -2,  3]

# 取出列(二维数组)
arr[:, [0]]
arr[:, 0, np.newaxis]
# [[-7],
#  [-2],
#  [ 3]]

# 取出列(返回一行)
arr[np.newaxis, :, 0]
# [[-7, -2,  3]]

# 取出多列
arr[:, [0, 2, 4]]
arr[:, 0::2]
# [[-7, -5, -3],
#  [-2,  0,  2],
#  [ 3,  5,  7]]

布尔索引、切片

类似本章前文,二维数组也可以采用布尔索引、切片。举个例子,如图 13 所示,取出二维数组大于 0 的元素,结果为一元数组。

import numpy as np

arr = np.arange(-7, 7+1).reshape(3, 5)

arr[arr > 0]
# [1, 2, 3, 4, 5, 6, 7]
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.5