「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
前言
我们前面已经对numpy ndarray进行深入学习了 numpy 内部结构。
- numpy 相比 python list 区别是 numpy 具有 ndarray 数据结构,可以创建N维数组。
- numpy 数据元素是同种类型的,所有每一个元素数据内存空间大小相同
- numpy 数组可以直接引用到数据本身,而不用像Python list 存放的是对象的引用,然后再通过引用找到具体的数据对象,。
- numpy 数组数据元素存储是一段连续的空间,极大的节省了内存消耗,而Python list 引用的数据对象的物理地址不是连续的。
如下图,我们可以看到 numpy 数组与Python list 清晰的比较
在我们之前学习Python list中,都知道列表可以通过元素位置-索引进行访问。同理,numpy 数组也同样与python list 类似,也是可以进行索引切片操作的。
我们在numpy 视图与副本中知道视图是与原数组共享数据,因此数组中进行索引切片,其实是返回的视图操作。
本期,我们将继续探索,numpy 数组索引切片的操作相关方法的学习,Let's go~
1. 索引概念
-
什么是索引?
在 Python 中,如list可以通过下标index访问指定位置的元素值,下标index就是索引。
同理,在numpy 数组中,可以使用标准的Python 数组[obj] 语法进行索引。
在进行索引切片操作时,numpy 内部是采取视图的形式进行的,当更改索引的内容时,将对原始数组的数据产生影响。因此,如果索引的值,如果要与原始数组数据相互独立,可以采用copy()副本形式拷贝一份完整数据。
-
索引的分类
按照数组中元素数据类型分类,可以四类:
- 基本索引
- 整数数组索引
- 布尔索引
- 花式索引
其中,整数数组索引、布尔索引、花式索引是属于高级索引的
2. 基本索引
-
单元素索引
我们可以使用类似 python list[index] 形式来进行索引工作。默认index从0开始。
同样,numpy 数组也可以支持 Python 列表一样从尾部开始进行负索引操作
例如,我们使用nump.arange()方法创建一个数组,通过单元数索引如arr[7]可以得到数据7
>>> import numpy as np >>> arr1 = np.arange(10) >>> arr1 array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> arr1[7] 7 >>> arr1[-2] 8 >>> arr1[0] 0 >>>对于多维度的数组,我们可以使用 "," 来进行索引查找
>>> import numpy as np >>> arr2 = np.arange(15) >>> arr2.shape = (3,5) >>> arr2 array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> arr2[2,3] 13 >>> arr2[-1,-1] 14 >>>对于多维的数组来说,我们填写的索引比多维数组维度小于时,是会按照row方式输出一个子维数组。
>>> arr2[0] array([0, 1, 2, 3, 4]) >>> -
单元素索引返回的是视图 or 副本?
首先对于一维数组如上述数组arr1来说,我们通过索引如arr1[7] 会得到数值7,那么arr1[7]是属于arr1数组的数据吗?
别急,我们还是按照之前metdata包含的指标,ndarray.flags.owndata 和 ndarray.base来看看真像是什么?
>>> print(arr1.flags.owndata) True >>> print(arr1[7].flags.owndata) True >>> print(arr1.base) None >>> print(arr1[7].base) None我们分别查看了 arr1 和 arr1[7] base和 flags.owndata 信息怎么都是一样的,因此arr1[7] 是与 arr1 原始数组相互独立的,是arr1 的副本
同时我们来id()方法来验证一下arr1 和 arr1[7] 内存地址,果然也不一样的
>>> id(arr1) 2182599900176 >>> id(arr1[7]) 2182320408080 >>>是不是同理推理,arr2[1,3] 也是arr2的数据相互独立的,返回的也是arr1副本
那么,arr2[0] 也是 arr2 的副本吗?
同样我们获取base、flags.owndata三个参数看看
>>> arr2[0] array([0, 1, 2, 3, 4]) >>> print(arr2.base) None >>> print(arr2[0].base) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] >>> print(arr2.flags.owndata) True >>> print(arr2[0].flags.owndata) Falsearr2[0].base 来源是 arr2 的,那么arr2[0] 与 arr2 是共享数据的,那么arr2[0]返回的是arr2的视图。
同时对于多维数组来说,我们 arr2[2,3] 等价于 arr2[2][3],都是返回数值13。
但是这样arr2[2][3] 较于 arr2[2,3] 效率上慢了许多。
arr2[2] 是 arr2 的一个视图,返回一个一维数组,arr2[2]基础上会创建一个新的临时数组arr2[2][3],最后得到一个单元素数值
3. 切片
-
什么是切片?
我们之前学习,Python 基本数据类型如列表、字符串,都使用过切片操作。因此,numpy 数组中也沿用了Python 内部的切片概念。
numpy 数组与Python 索引一样,所有索引都是从0开始的,返回一个有效范围内的数组。
基本切片的生成的数组始终都是原始数组的视图
-
触发切片的条件
- obj 是一个由(star:stop:step)组成的slice 对象
- 与整数、或者切片对象和整数元组
- 可添加省略号对象(Ellipsis)和 维度方向(newaxis)对象
-
切片的操作方法
- 形式如i:j:k,i为起始索引,j为终止索引,k为步长
- 使用slice方法
-
-
使用 : 来进行切片
可以像Python list一样使用
:进行切片操作,同样支持正索引和负索引-
当i,j,k都为正整数时,进行正索引,如下栗子:
>>> arr3 = np.arange(10) >>> arr3 array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> arr3[1:6:2] array([1, 3, 5]) -
当i为负数,k也负数走向更小的索引
>>> arr3[-2:3:-2] array([8, 6, 4]) >>> -
只设置i,则从i开始切片
>>> arr3[1:] array([1, 2, 3, 4, 5, 6, 7, 8, 9]) -
::这与:和 表示选择沿该轴的所有索引>>> arr3[::] array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>>
-
-
使用 slice() 索引
我们也可以slice方法设置索引对象,从而对数组来进行索引切片操作
>>> arr3[slice(1,6,2)] array([1, 3, 5]) >>>
总结
本期,我们对 numpy 模块中基本索引切片相关方法进行学习。对于单元素索引中,对于一维数组的索引返回的对象是原始数组的副本,而对于多维数组来说,当索引少于其维度时,返回的索引对象是原始数组的视图。
对于,切片操作来说,不适用在高级索引。
以上是本期内容,欢迎大佬们点赞评论,下期见~