我们先来看看一阶数组的切片索引
import numpy as np arr = np.arange(10) print(arr) print(arr[5]) print(arr[5:8]) [0 1 2 3 4 5 6 7 8 9] 5 [5 6 7]
注意:数组的切片得到的是一个原始数组的一个视图,即原始数据并没有被复制而形成新的拷贝,视图上的任何修改都会直接反应到原始数组之上,这和python内置列表是有很大区别
import numpy as np arr = np.arange(10) arr[5:8] = 999 print(arr) [ 0 1 2 3 4 999 999 999 8 9]
import numpy as np arr = np.arange(10) temp = arr[5:8] temp[1] = 888 print(arr) [ 0 1 2 3 4 5 888 7 8 9]
这样做的原因是,numpy的设计目的是处理大数据,避免数据的反复复制有利于节省内存、提升性能。
如果执意要获得ndarray切片的一份副本而非视图,则需要显式的进行复制操作。
import numpy as np arr = np.arange(10) temp = arr[5:8].copy() temp[1] = 888 print(arr) [0 1 2 3 4 5 6 7 8 9]
高维数组的索引
在一个二维数组中,显而易见的是,各索引位置上的元素不再是标量而是一维数组
import numpy as np arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) print(arr2d[2]) print(arr2d[0,1]) print(arr2d[0][1]) [7 8 9] 2 2
更高阶的数组
import numpy as np arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) print(arr3d[0]) print(arr3d[1][0]) print(arr3d[0][0][1]) [[1 2 3] [4 5 6]] [7 8 9] 2 #我们看其中,arr3d[1][0]: #第一个索引“1”:把[[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]最外层的中括号去掉, #[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]],得到[[7,8,9],[10,11,12]],第二个索引“0”,再去掉一个中括号[7,8,9],[10,11,12],得到结果[7,8,9]
和前面描述的类似,ndarray利用索引返回的低维数组子集也是视图而非拷贝,获取拷贝也需要显式的调用copy函数。标量和等维的数组都可以对数据进行赋值。
import numpy as np arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) arr3d[0] = 111 print(arr3d) [[[111 111 111] [111 111 111]] [[ 7 8 9] [ 10 11 12]]] import numpy as np arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) arr_cpy = arr3d[0].copy() arr3d[0] = 111 print(arr3d) [[[111 111 111] [111 111 111]] [[ 7 8 9] [ 10 11 12]]] arr3d[0] = arr_cpy print(arr3d) [[[ 1 2 3] [ 4 5 6]] [[ 7 8 9] [10 11 12]]]
import numpy as np arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) print(arr2d[:2,1:]) [[2 3] [5 6]] #同理,从左到右的切片索引,就是从外到内处理中括号的过程, #第一个“:2”高维度的切片,是对高维进行切片,即选取第0行和第1行(左闭右开),得到[[1,2,3],[4,5,6]] #第二个“1:”则是在此基础上对低维进行切片,即第一列到最后一列。最终得到结果。
当然切片和整数索引是可以混用的
import numpy as np arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) print(arr2d[:2,1]) [2 5]
通过切片获取的也是原始数组的一个视图,并且对切片表达式进行赋值操作,也是扩散到整个选区
import numpy as np arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) arr2d[:2,1:] = 0 print(arr2d) [[1 0 0] [4 0 0] [7 8 9]]
布尔索引
我们先看一个例子,对一个数组进行==判定操作,会得到一个等维度的bool数组
import numpy as np names = np.array(['tom','bob','bill','jack','tom']) arr_bool = names == 'tom' print(arr_bool) [ True False False False True]
这个得到的bool型数组可以用于数组索引,前提是bool型数组的长度和被索引数组的高维维度一致
import numpy as np names = np.array(['tom','bob','bill','jack','tom']) arr_bool = names == 'tom' data = np.random.rand(5,3) print(data) print(data[arr_bool]) [[ 0.09769032 0.97245502 0.1762949 ] [ 0.59949381 0.46735516 0.64142579] [ 0.45941574 0.06747531 0.55780872] [ 0.29714417 0.78494754 0.5194105 ] [ 0.78078671 0.96654222 0.27489762]] [[ 0.09769032 0.97245502 0.1762949 ] [ 0.78078671 0.96654222 0.27489762]]
当然,显而易见的是,bool型数组也是可以和切片、整数索引混用的
import numpy as np names = np.array(['tom','bob','bill','jack','tom']) data = np.random.rand(5,3) print(data) print(data[names == 'tom',1:]) [[ 0.16915065 0.15038684 0.34028728] [ 0.32732646 0.69241855 0.65203056] [ 0.84402175 0.77184234 0.48730057] [ 0.94376757 0.33876278 0.77287885] [ 0.58535219 0.50321862 0.28196336]] [[ 0.15038684 0.34028728] [ 0.50321862 0.28196336]]
通过bool型索引选取数组中的数据,将总是创建数据的副本,而非视图
同时可以利用布尔型数组进行条件赋值,这也是会经常用到的
import numpy as np names = np.array(['tom','bob','bill','jack','tom']) data = np.random.rand(5,3) print(data) data[data<0.5]=0 print(data) [[ 0.11395235 0.30461958 0.02896975] [ 0.54829738 0.25386957 0.71327458] [ 0.95840718 0.01013043 0.75231583] [ 0.1600976 0.09872024 0.96804632] [ 0.16516135 0.44308404 0.90036341]] [[ 0. 0. 0. ] [ 0.54829738 0. 0.71327458] [ 0.95840718 0. 0.75231583] [ 0. 0. 0.96804632] [ 0. 0. 0.90036341]]
也可以利用一维bool数组进行整行、整列的赋值
import numpy as np names = np.array(['tom','bob','bill','jack','tom']) data = np.random.rand(5,3) print(data) data[names == 'tom']=0 print(data) [[ 0.45025316 0.63122953 0.92612377] [ 0.02918047 0.72361626 0.50190505] [ 0.97611338 0.92807698 0.60883423] [ 0.40124052 0.81103418 0.05447573] [ 0.07352045 0.16173038 0.28114157]] [[ 0. 0. 0. ] [ 0.02918047 0.72361626 0.50190505] [ 0.97611338 0.92807698 0.60883423] [ 0.40124052 0.81103418 0.05447573] [ 0. 0. 0. ]]
关于多维数组的索引,我们最后看一种用法,利用整数数组进行索引:
按照整数数组中的索引值,来依次选取对应行
import numpy as np arr = np.empty((8,4)) for i in range(8): arr[i] = i print(arr) print(arr[[4,3,0,6]]) [[ 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.]] [[ 4. 4. 4. 4.] [ 3. 3. 3. 3.] [ 0. 0. 0. 0.] [ 6. 6. 6. 6.]]
在此基础上,再选取对应列,也是不难的
第一种情况是,针对每一行选取特定的列
import numpy as np arr = np.arange(32).reshape(8,4) print(arr) print(arr[[1,5,7,2],[0,3,1,2]]) [[ 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]] [ 4 23 29 10]
可以看出,是在选取的特定四行后,再在每一行中挑选出指定的值,最后结果就是四个数
第二种使用场景是,在按照指定顺序选取行后,再按指定顺序选取整列
import numpy as np arr = np.arange(32).reshape(8,4) print(arr) print(arr[[4,3,0,6]][:,[0,3,1,2]]) [[ 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]] [[16 19 17 18] [12 15 13 14] [ 0 3 1 2] [24 27 25 26]]