1.3 - Numpy数组的切片和索引
1.3.1 列表和数组(矩阵)的 索引/切片
虽然可以通过列表生成数组,但是要注意:列表永远是一维的,只有数组才有多维的概念。
切片是多个索引,所以,切片本质也是索引。
列表切片会拷贝一份原列表的数据,而切片数组则会返回原数组的视图。因为numpy的主要是处理大数据,如果每次切片都进行一次复制,那对性能和内存是相当大的考验。
可以通过 索引和切片 对数组元素进行改动。
索引会降维,切片不会降维。 可以理解为:普通索引只取出序列中一个下标对应的元素,这种情况下会降维;而切片取出序列中多个下标对应的元素,单个的索引会降维,但是因为有多个索引需要用括号括起来,这样又会新生成一个维度,所以不会降维。(注:只要是用 冒号:或省略号... 获取的索引,都叫做切片,不管切出来的是一个元素还是多个元素!!!)
import numpy as np lst = [1, 2, 3, 4, 5] arr = np.array(lst) item_lst = lst[::2] # 创建列表切片 item_arr = arr[::2] # 创建数组切片 print(item_lst) print(item_arr) # 分别修改 列表和数组 的元素 lst[0] = 11 arr[0] = 11 print(item_lst) # 列表切片不变 print(item_arr) # 数组切片改变了, 说明数组切片是原数组的动态视图。 # 通过 索引 改动数组元素 arr[0] = 111 print(arr) # 数组的值改变了 # 通过 切片 改动数组元素 arr[::2] = 222 print(arr) # 数组的值改变了
1.3.2 一维数组的索引和切片
数组的最后一个元素的索引为 -1。
import numpy as np arr = np.arange(10) print(arr) # 一维数组的索引,索引降维 print(arr[0], arr[-1]) # 一维数组的切片,切片不降维 print(arr[::2])
1.3.3 多维数组的索引和切片
分析多维数组的切片结果时,先确定切片后的shape。
对多维数组切片: 无论是对多维数组的每个轴索引还是对整个数组索引,都是:遇到单个索引降维,遇到多个索引的切片不降维
import numpy as np arr = np.arange(6).reshape(3, 2) print(arr) # 多维数组的索引 print(arr[0][0]) # 多维数组索引的第一种方式 print(arr[0, 0]) # 多维数组索引的第二种方式 # 多维数组的切片 print(arr[::2]) # 没有逗号,不是轴索引。结果就相当于对数组的第一维进行普通的一维列表索引,只是一维列表的元素变成了一个长度为2的列表 print(arr[:2][1:2]) # 对整个多维数组连续切片(过程中只对第一维进行了索引) print(arr[:][1]) # [:]是个切片不降维:shape(3,2),[1]是个索引会降维:shape(2,), 最终结果:[2,3] print(arr[:, 1:2]) # :是个切片取第一个轴的所有元素并保留这个轴,1:2切片取第二个轴的第二列元素并保留这个轴。shape(3,1) print(arr[..., 1]) # ...切片取第一个轴的所有元素并保留这个轴,1索引取第二个轴的第二列元素并消除这个轴。shape(3,)
1.3.4 多维数组的高阶索引
1)列表索引
因为列表本身便意味着会包含多个元素,相当于多个索引,所以在索引完成后会在外面套上一层括号。列表索引也不会降维。
第一个列表索引第一个轴,第二个列表索引第二个轴...。如果只有一个列表,那么只会索引第一个轴;如果有多个列表,这些列表会进行拉链,根据拉链生成的元组对数组进行索引并在最后完成索引后套上括号升维。
对数组的每个轴进行索引的列表也可以是多维的,索引不同轴的多个 多维索引列表也会进行拉链,并且当每个轴索引数组的size不匹配导致无法拉链的时候也会发生广播。
import numpy as np arr = np.arange(18).reshape(3, 2, 3) print(arr) # 数组高阶索引 - 单个列表索引 => 相当于 arr[0] arr[0] arr[0] 三个数组堆叠成一个新的数组 print(arr[[0, 0, 0]]) # 数组高阶索引 - 多个单维列表索引 =》 多个单维索引列表拉链构成对数组的每个轴的索引 print(arr[[0, 1, 0], [1, 0, 0]]) # shape: (3, 3) print(arr[[0, 1, 0], [1, 0, 0], [0, 1, 1]]) # shape: (3, ) # 数组高阶索引 - 在对数组的每个轴进行索引的时候,可以使用多维数组 arr1 = np.arange(4).reshape(2, 2) print(arr1[ [[0, 0],[1, 1]], [[0, 1],[0, 1]]]) # shape: (2, 2) print(arr[ [[0, 0],[1, 1]], [[0, 1],[0, 1]]]) # shape: (2, 2, 3)
2)bool数组索引
bool数组索引,比如对一个shape为 (3, 2, 3)的数组进行bool数组索引,如果想要原数组的某些单个元素,则创建一个 shape为(3,2,3)的bool数组并将对应位置的元素置为True;
如果想要原数组中的某些一维数组,则创建一个shape为(3,2)的bool数组,将想要的那个一维数组在原数组中的坐标在bool数组的对应位置元素置为True;如果想要原数组中的某些二维数组,则创建一个shape为(3,)的bool数组,将想要的那个二维数组在原数组中的坐标在bool数组对应位置的元素置为True。
import numpy as np arr = np.arange(18).reshape(3, 2, 3) print(arr) bool_lst = [[True, False], [False, True], [True, True]] bool_index = np.array(bool_lst) print(arr[bool_index]) # bool数组中有四个位置的元素为True,且每个位置元素对饮一个一维数组,所以shape: (4, 3)
1.3.5 高阶索引和基本切片混合
对shape为 (3, 2, 3)的数组arr,混合索引arr[::2, [0, 1, 0], [1, 0, 2]] ,切片对第一维切出了2个,高阶索引索引到了三个单个元素,所以shape(2, 3);arr[ [0, 1, 0], ::2, [1, 0, 2] ] 高阶索引对第一个维度索引了3个元素并和后面的高阶索引形成拉链拉出来了3个单个元素,切片对第二维切出了两个元素,所以shape(3,2)。
只有高阶索引和基本索引之间会发生广播,高阶索引和切片之间不会发生广播!!!!! 切片是切一个维度,高阶索引之间会形成拉链,二者各干各的,互补干预。!!!
总之牢记:对数组的每个轴索引时,切片不降维,索引会降维且多个不同轴的索引列表之间会拉链。
import numpy as np arr = np.arange(24).reshape(4, 2, 3) print(arr) # 高阶索引和切片混合,第一个维度切片切出来两个,剩下两个轴的两个索引列表进行拉链而索引到3个元素,shape(2,3) print(arr[::2, [1, 0, 0], [1, 1, 1]]) print(arr[[1, 0, 0], [1, 1, 1], ::2]) # 同理,shape(3, 2) print(arr[[1, 0, 0], ::2, [1, 1, 1]]) # shape(3,1) x = np.arange(48).reshape(4, 2, 3, 2) print(x) print(x[[1, 0, 0], ::2, [1, 1, 1]]) # shape(3, 1, 2)