0. 引言
在学习cv2.kmeans函数的时候,第一次遇到花式花式索引的操作。刚开始理解的时候有些迷糊,因此记录一下。
1. 定义
花式索引(也称为高级索引)是一种在 NumPy 中用于通过索引数组选择子集的方法。与基本的切片索引不同,花式索引可以用于选择任意形状的子集,包括不连续的、重复的、任意形状的子集。
使用花式索引可以通过传递一个或多个索引数组来选择数组中的元素。索引数组可以是整数、布尔值或其它数组,它们的形状可以与被索引数组不同。如果索引数组是整数或布尔值,它们会被解释为元素在被索引数组中的位置。如果索引数组是其它数组,它们会被解释为元素在被索引数组中的坐标。
2. 操作
主要可以分为一维索引和多维索引。
2.1 一维索引:
可以使用一个一维数组来索引另一个数组。在这种情况下,结果将是一个新的数组,其形状与索引数组相同,其中每个元素是被索引数组中对应下标的值。
- 用序列(list)索引序列(list)
代码:
import numpy as np
a = np.array([1, 2, 3, 4, 5])
idx = np.array([0, 3, 4])
b = a[idx]
print(b) # 输出[1 4 5]
上面的例子比较好理解,idx中存的数据为被索引序列的位置,从0开始计数。
- 用序列(list)索引数组(array)
代码:
import cv2
a = np.array([[1,2,3],[0,0,0]])
print('a =',a)
print('shape of a=',a.shape)
print('--------------------------------')
idx = [0,0,1,1,1,1]
print('idx =',idx)
print('length of idx=',len(idx))
print('--------------------------------')
c = a[idx]
print('c =',c)
print('shape of c=',c.shape)
'''
输出结果:
a = [[1 2 3]
[0 0 0]]
shape of a= (2, 3)
--------------------------------
idx = [0, 0, 1, 1, 1, 1]
length of idx= 6
--------------------------------
c = [[1 2 3]
[1 2 3]
[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
shape of c= (6, 3)
'''
idx中储存的值为被索引数组的行号。0表示索引第0行,1表示索引第1行。如果索引值超出被索引数组的行数,将报错:IndexError: index 2 is out of bounds for axis 0 with size 2
2.2 高维索引:
可以使用一个多维数组来索引另一个数组的多个元素。在这种情况下,结果将是一个新的数组,其形状与索引数组的形状相同,其中每个元素是被索引数组中对应下标的值。
高维索引可以用数组索引数组,但要分两种情况。
- 一个index数组
代码:
import numpy as np
# 例1:行索引,和list一样
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([0, 2])
c = a[b, :] # 选择第 0、2 行的所有元素
print('index of row')
print('c = \n',c)
print('shape of c =',c.shape)
print('-----------')
# 例2:列索引
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([0, 2])
c = a[:, b] # 选择第 0、2 列的所有元素
print('index of column')
print('c = \n',c)
print('shape of c =',c.shape)
print('-----------')
# 例3:行列索引
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([[0, 1], [1, 0]])
c = a[b]
print('index of row and column')
print('c = \n',c)
print('shape of c =',c.shape)
'''
输出结果:
index of row
c =
[[1 2 3]
[7 8 9]]
shape of c = (2, 3)
-----------
index of column
c =
[[1 3]
[4 6]
[7 9]]
shape of c = (3, 2)
-----------
(2, 2)
index of row and column
c =
[[[1 2 3]
[4 5 6]]
[[4 5 6]
[1 2 3]]]
shape of c = (2, 2, 3)
'''
上述代码中,前两个例子理解起来没有问题:输入的是1*n的一维数组,和列表的作用一样,索引数组的行数或列数。
注意:一维数组的shape为(n,)
例3中,当输入的是多维数组时,结果有一些复杂:被索引的数组是2维数组,但结果变成了3维。
例3的结果和下面代码中的结果一致:
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([[0, 1], [1, 0]])
c = a[b,:]
print('index of row and column')
print('c = \n',c)
print('shape of c =',c.shape)
'''
输出结果:
index of row and column
c =
[[[1 2 3]
[4 5 6]]
[[4 5 6]
[1 2 3]]]
shape of c = (2, 2, 3)
'''
即c = a[b]等价于c = a[b,:],都是对数组a的行进行索引操作 。
可以从结果c中看出,当索引b是2维的时候,将扩展结果c的第0维。
例如,
c[0,:,:] 表示 [[1 2 3],[4 5 6]]
对应于索引b第0行的[0,1]获取的数组a的第0行与第1行的值。
c[1,:,:]表示 [[4 5 6],[1 2 3]]
对应于索引b第1行的[1,0]获取的数组a的第1行与第0行的值。
可知,索引b的行数决定结果c第0维数据的宽度。例如,将索引b的行数增加为3行,c.shape将变为(3,2,3):
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# b = np.array([[0, 1], [1, 0]])
b = np.array([[0, 1],[1,0],[0,0]])
c = a[b,:]
print('index of row and column')
print('shape of b:',b.shape)
print('c = \n',c)
print('shape of c =',c.shape)
'''
输出结果:
index of row and column
shape of b: (3, 2)
c =
[[[1 2 3]
[4 5 6]]
[[4 5 6]
[1 2 3]]
[[1 2 3]
[1 2 3]]]
shape of c = (3, 2, 3)
'''
如果增加索引b的列数,将改变结果c的第1维数据的宽度。例如将索引b改为2行3列,c.shape将变为(2,3,3):
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# b = np.array([[0, 1], [1, 0]])
# b = np.array([[0, 1],[1,0],[0,0]])
b = np.array([[0, 1, 0],[1,0, 0]])
c = a[b,:]
print('index of row and column')
print('shape of b:',b.shape)
print('c = \n',c)
print('shape of c =',c.shape)
print(c[0,:,:])
'''
输出结果:
index of row and column
shape of b: (2, 3)
c =
[[[1 2 3]
[4 5 6]
[1 2 3]]
[[4 5 6]
[1 2 3]
[1 2 3]]]
shape of c = (2, 3, 3)
c[0,:,:]=
[[1 2 3]
[4 5 6]
[1 2 3]]
'''
- 两个index数组
- 两个1维数组
- 两个多维数组
未完待续