1.基础索引与切片
1.1视图与副本
在numpy中的切片与索引,都是原数组的一个视图,也就是说,进行任何切片或者索引操作并不会产生一个新的数组,都是在原数组的基础上操作,这与其他语言的对象很像,而非一个基本类型。如下例:
arr = np.array([1, 2, 3, 4, 5])
view = arr[1:4]
view[0] = 20
print(arr) # 输出: [ 1 20 3 4 5]
而拷贝需要显式的利用.copy函数完成。如下例子:
arr = np.array([1, 2, 3, 4, 5])
copy = arr[1:4].copy()
copy[0] = 20
print(arr) # 输出: [1 2 3 4 5]
1.2索引与切片
一维数组的索引与切片和python原生的序列数组的使用是一样的,对于索引第
x
x
x位元素,则使用arr[
x
−
1
x-1
x−1](从0开始标号),而切片arr[
x
x
x,
y
y
y]则表示为arr[
x
x
x]到arr[
y
−
1
y-1
y−1]的数据元素。
而对于更高维度的数组,可以通过arr[
x
x
x][
y
y
y][
z
z
z]······或者arr[
x
x
x,
y
y
y,
z
z
z,······]逐级索引,每增加一个索引值就是将原数组降低一个维度,如下例:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]
arr2d[0][2]
arr2d[0, 2]
而对于切片也是类似的,与python原生的序列类型相似,困难点在于对于axis的理解,针对高维数据的理解可以看: 高维数组对象的理解,但是需要注意的是在日常使用中,多数数据类型为二维和三维数据,对于更高维度的索引与切片在本文以及后续文章中将不再详细说明,关注点放在二维与三维数据即可。
adarry的切片可以总结如下:对于任意维度,以start:stop:step的形式进行切割。当步长为1时,可以省略step,同样当从头开始到某处截止或者时从某处开始到结束可以省略start或者stop,如下所示:
arr2d
arr2d[:2]
arr2d[:2, 1:]
arr2d[1, :2]
arr2d[:2, 2]
arr2d[:, :1]
2.特殊索引
2.1布尔索引
要想理解布尔索引,得讲一个故事:首先构建一个name数组和data数组,假设在真实的世界中,name和data一一对应,,那么如何可以通过name数组筛选出对应的data数据?
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
names
data
#name:array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')
'''data:array([[-0.2047, 0.4789, -0.5194, -0.5557],
[ 1.9658, 1.3934, 0.0929, 0.2817],
[ 0.769 , 1.2464, 1.0072, -1.2962],
[ 0.275 , 0.2289, 1.3529, 0.8864],
[-2.0016, -0.3718, 1.669 , -0.4386],
[-0.5397, 0.477 , 3.2489, -1.0212],
[-0.5771, 0.1241, 0.3026, 0.5238]])'''
names == 'Bob'
#array([ True, False, False, True, False, False, False])
data[names == 'Bob']
#array([[-0.2047, 0.4789, -0.5194, -0.5557],
# [ 0.275 , 0.2289, 1.3529, 0.8864]])
可以看到直接通过数组和值的比较操作就可以完成整体的布尔判断,返回的也是array,而对于数组的索引,也可以使用array来进行索引。
在进行布尔索引的过程中需要注意的是:1. 布尔数组的长度必须和数组某个轴方向的长度一致;2.与(&)或(|)3.若要取非可以使用!=表示不等,或者在条件前加~:
data[~(names == 'Bob')]
2.2 神奇索引
通过传递一个顺序列表或者数组可以直接完成符合特定顺序的子集,如下例:
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i
arr
'''
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
'''
arr[[4, 3, 0, 6]]
'''
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
'''
arr[[-3, -5, -7]]#也可以是负数,从后向前
'''
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
'''
arr = np.arange(32).reshape((8, 4))
arr
arr[[1, 5, 7, 2], [0, 3, 1, 2]]
'''
array([[ 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]])
array([ 4, 23, 29, 10])
'''
arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
'''
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
'''
需要注意的是,和基础切片与索引极为相似,但是少了一层中括号,即基础切片与索引中是arr[ x x x, y y y, z z z,······],而神奇索引是arr[[ x x x, y y y, z z z,······]]