无法播放?请 点击这里 跳转到Youtube
切换视频源:

上一章我们学习了如何使用一些NumPy常用的方法创建数组,今天我们来学习操作数组非常重要的一个内容:索引(indexing)。

数组的索引指的是定位数据元素,不仅仅是定位单个元素,也可以定位多个元素。

一维数组索引

基本的索引是通过方括号 [] 实现的,如果括号中放置一个参数,则返回与该索引相对应的单个元素。如果是 [2: ],表示从该索引开始以后的所有元素都被提取。如果使用了两个参数,比如 [2:10],表示提取两个索引位置 (不包括右边索引元素) 之间的所有元素。

array = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(array)

print(array[2:5]) # 第3个元素到第5个元素(不包括第五个元素) [2 3 4]

print(array[:5]) # 第1个元素到第5个元素 [0 1 2 3 4]

print(array[:-3]) # 第1个元素到倒数第4个元素(不包括倒数第3个元素) [0 1 2 3 4 5 6]

print(array[3:-1]) # 第4个元素到倒数第2个元素(不包括倒数第1个元素)[3 4 5 6 7 8]

print(array[3:-3]) # 第4个元素到倒数第4个元素 [3 4 5 6]

print(array[::-1]) # 颠倒NumPy的数组 [9 8 7 6 5 4 3 2 1 0]

print(array[2:7:3]) # 从第3个元素到7个元素(不包括第7个元素),间隔为3 [2 5]

print(array[-3:3:-1]) # 从倒数第3个元素(7),到第5个元素(4),回跳一个位置 [7 6 5 4]

二维矩阵索引

matrix_1 = np.arrange(20).reshape(4, 5) # 创建一个 4 * 5 的矩阵,取值范围在 0~19
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]

matrix_1[0, 3] # 第1行第4列的元素:3

matrix_1[0, 1] = 100 # 第1行第2列的元素变成 100
[[  0 100   2   3   4]
 [  5   6   7   8   9]
 [ 10  11  12  13  14]
 [ 15  16  17  18  19]]

matrix_1[2, :] # 第3行的所有元素 [10 11 12 13 14]

matrix_1[:, 2] # 第3列的所有元素 [ 2  7 12 17]

matrix_1[1:3, 2:4] # 第2行到第3行,第3列到第4列的子矩阵
[[ 7  8]
 [12 13]]

我们还能使用多个数组,来定位各个维度上的位置,拿到特定位置的元素:

matrix_1[[0, 2, 2], [0, 1, 0]] # 返回3个元素 [0 11 10] 第1个元素位置是[0,0],第2个元素位置是[2,1],第3个元素位置是[2,0]

matrix_1[[1, 0, 2], [1, 1, 1]] # 返回3个元素 [6 100 11] 第1个元素位置是[1,1],第2个元素位置是[0,1],第3个元素位置是[2,1]

matrix_1[(0, 3), 2:5] # 第1行和第4行,列数3到5
[[2, 3, 4],
 [17, 18, 19]]

多维数组索引 Ellipsis(…)

切片操作中还能使用省略号 ,使得子数组维度的长度与原数组的维度相同,使用…可以包含未显性定义维度的所有内容。

matrix_3d = np.arange(80).reshape(4, 5, 4)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]
  [12 13 14 15]
  [16 17 18 19]]

 [[20 21 22 23]
  [24 25 26 27]
  [28 29 30 31]
  [32 33 34 35]
  [36 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]]]

matrix_3d[2, ...] # 矩阵3中所有的元素
[[40 41 42 43]
 [44 45 46 47]
 [48 49 50 51]
 [52 53 54 55]
 [56 57 58 59]]

matrix_3d[0, 2, ...] # 矩阵1中,第3行所有的列
[ 8  9 10 11]

matrix_3d[3, ..., 2] # 矩阵4中,所有行,第3列
 
matrix_3d[3, :, 2] # 矩阵4中,所有行,第3列

对于多维数组,我们也能使用多个数组,来定位各个维度上的位置,定位到特定位置的元素:

matrix2 = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(matrix2)
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]

vector = np.array([0, 2, 0, 1])
print(matrix2[np.arange(4), vector]) # 拿到以下4个位置的元素: [0,0],[1,2],[2,0],[3,1]
[ 1  6  7 11]

matrix2[np.arange(4), vector] += 10 # 给特定位置上的元素加10
print(matrix2)
[[11  2  3]
 [ 4  5 16]
 [17  8  9]
 [10 21 12]]

布尔索引(Boolean Indexing)

学习了基本的索引操作,接下来我们来学学如何使用布尔数组来定位numpy数组。

matrix3 = np.array([[1, 2], [3, 4], [5, 6]])
bool_idx = matrix3 > 2 # 拿到一个布尔数组,其中元素代表相应位置的元素是否大与2
[[False False]
 [ True  True]
 [ True  True]]

matrix3[bool_idx] # 使用布尔数组,获取矩阵中大于2的值
[3 4 5 6]

matrix3 = np.arange(0, 15).reshape(3, 5)
matrix3[matrix3 > 2] # 拿到矩阵中所有大于2的元素
[ 3  4  5  6  7  8  9 10 11 12 13 14]

print(matrix3[matrix3 % 2 == 1]) # 拿到矩阵中所有不能整除2的元素(奇数)
[ 1  3  5  7  9 11 13]

我们也能使用多个布尔数组,通过 ix_ 函数来索引不同维度上的数据

matrix4 = np.arange(36).reshape(3, 12)
[[ 0  1  2  3  4  5  6  7  8  9 10 11]
 [12 13 14 15 16 17 18 19 20 21 22 23]
 [24 25 26 27 28 29 30 31 32 33 34 35]]

rows_on = [True, False, True]
cols_on = np.arange([False, True, False] * 4)

matrix4[np.ix_(rows_on, cols_on)]) # 拿到一个特定的子矩阵:第一个维度位置是1和3,第二个维度位置是1,4,7,10
[[ 1  4  7 10]
 [25 28 31 34]]

迭代 (Iterating)

学完如何索引数组之后,最后我们来学习一下如何迭代数组

two_d_matrix = np.arange(24).reshape(2, 12)

for row in two_d_matrix: # 迭代row
    print(row)
[ 0  1  2  3  4  5  6  7  8  9 10 11]
...

for column in two_d_matrix.T: # .T会转置矩阵,然后迭代row,就会迭代原来的col
    print(column)
[ 0 12]
[ 1 13]
...

three_d_matrix = np.arange(24).reshape(2, 3, 4)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
for item in three_d_matrix: # 迭代每个矩阵
    print(item)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
...
for item in three_d_matrix.flat: # 迭代所有的元素
    print(item)

课后练习答案

创建一个函数处理以下这个包含0-44的三维数组,将第2个矩阵中,第1行和第3行,第2~4列的元素变为1。然后在把数组中所有的奇数变为1,所有偶数变成0。最后再把矩阵的形状变成(9,5)。

np_array = np.arange(45).reshape((3,3,5))

答案

def np_operator(input_array):
  input_array[1, (0, 2), 1:4] = 1
  print(input_array)
  input_array[input_array % 2 == 1] = 1
  input_array[input_array % 2 == 0] = 0
  print(input_array)
  input_array.shape = (9, 5)
  print(input_array)
  return input_array

new_np_array = np_operator(np_array)