文章目录
- 一、通过索引访问数组元素
- 一维数组
- 二维数组
- 二、NumPy中的切片访问
- slice()函数
- 冒号分隔
- 三、二维数组的转置与展平
- transpose()函数 —— 转置
- ravel()方法 —— 降维
- flatten()函数 —— 降维
- shape() —— 显式变形
一、通过索引访问数组元素
一维数组
如果把数组名称当作访问数组的起始“指针”(pointer),那么索引就可以理解为偏离这个指针的偏移量(offset)。因此,正向索引时,第1个元素的索引是0(因为指针指向当前元素,不需要偏移,或者偏移量为0),第2个元素的索引是1(相对起始地址偏移量为1),以此类推。除此之外,数组同样支持反向索引,这时索引编号不存在直觉位置“差1”的情况,即方括号内的偏移量为-1表示倒数第1个元素,偏移量为-2表示倒数第2个元素,以此类推。
import numpy as np
one_dim = np.linspace(-0.5, 0.6, 12)
print("\n打印数组:\n{}".format(one_dim))
print("\n访问第一个元素:\n{}".format(one_dim[0]))
print("\n访问倒数第一元素\n{}".format(one_dim[-1]))
one_dim[0] = 1
print("\n对第一个元素赋值后打印数组\n{}".format(one_dim))
=================================================
打印数组:
[-0.5 -0.4 -0.3 -0.2 -0.1 0. 0.1 0.2 0.3 0.4 0.5 0.6]
访问第一个元素:
-0.5
访问倒数第一元素
0.6
对第一个元素赋值后打印数组
[ 1. -0.4 -0.3 -0.2 -0.1 0. 0.1 0.2 0.3 0.4 0.5 0.6]
二维数组
相应地,访问二维数组时,需要通过两个索引来执行相应操作。访问二维数组的方式有两种,第一种是类似于C、C++一样,使用两个方括号,每个方括号对应一个维度信息。示例代码如下。
two_dim = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print("\n打印二维数组:\n{}".format(two_dim))
print("\n打印二维数组第0行第2列:\n{}".format(two_dim[0][2]))
====================================
打印二维数组:
[[1 2 3]
[4 5 6]
[7 8 9]]
打印二维数组第0行第2列:
3
事实上,NumPy提供了另一种更为简便的访问方式—把两个方括号合并,在一个方括号内分别给出两个维度信息,不同维度信息间用逗号(,)隔开。
print("\n使用numpy的two_dim[0, 2]方法打印:\n{}".format(two_dim[0, 2]))
================================
使用numpy的two_dim[0, 2]方法打印:
3
使用这种方法修改二维数组中的值:
two_dim[0, 2] = 100
print("\n打印修改之后的二维数组\n{}".format(two_dim))
===========================================
打印修改之后的二维数组
[[ 1 2 100]
[ 4 5 6]
[ 7 8 9]]
二、NumPy中的切片访问
与Python中列表的操作类似,除了通过索引访问数组元素,在NumPy中还可以通过切片操作来访问和修改数组数据。通过切片操作,我们可以批量获取符合要求的元素。切片操作的核心是从原始数组中,按照给定规则提取出一个新的数组,对原始数组没有任何影响。
slice()函数
#################### 切片
a = np.arange(10)
# 创建切片对象
s = slice(0, 9, 2)
# 按照切片规则提取数据
b = a[s]
print(b)
print(a)
=========================
[0 2 4 6 8]
[0 1 2 3 4 5 6 7 8 9]
我们通过slice()函数实例化一个切片参数,它表示从索引0开始到索引9停止,间隔为2,最后输出的结果为由0~9之间的偶数所组成的数组。
冒号分隔
切片更为简便的使用方法是,直接通过冒号分隔切片参数,而无须使用slice()函数。这时,切片规则通常是这样的:数组名[start🔚step]。其中start表示起始索引(从0开始),end表示结束索引(至-1结束),step表示步长,步长为正时表示从左向右取值,步长为负时则反向取值。
print(a[0:9:2])
print(a)
===========================
[0 2 4 6 8]
[0 1 2 3 4 5 6 7 8 9]
需要注意的是,通过冒号分隔切片参数来进行切片操作时,假设方括号内索引值后面加上一个冒号,则表示从该索引开始,后面的所有项都将被提取。如a[2:]表示从第3个元素开始直到最后的所有元素,全部提取(这里索引是从0开始的,下同)。
print(a[2:])
==============
[2 3 4 5 6 7 8 9]
如果使用了两个参数,那么冒号前面的参数为start,后面的参数为stop,提取出的数值为两个索引值之间的项(取值区间左闭右开,不包括结束索引),默认步长为1时可以省略。示例如下。
print(a[2:-2])
===========================
[2 3 4 5 6 7]
切片的步长step可取负值。当step=−1时,start: end: −1表示从start开始逆序读取至end结束(不包含end)。考虑最特殊的一种例子,当切片方式为“::-1”时就完成了逆序读取。代码如下所示。
print(a[::-1])
=========================
[9 8 7 6 5 4 3 2 1 0]
三、二维数组的转置与展平
transpose()函数 —— 转置
我们可以通过transpose()方法将二维数组转置,代码如下。但这种转置仅仅得到原有二维数组的视图,原始数组并没有发生变化。
two_dim = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print("\n对二维数组进行转置:\n{}".format(two_dim.transpose()))
print("\n使用大写T也可以完成转置:\n{}".format(two_dim.T))
print("\n对原数组无影响:\n{}".format(two_dim))
===========================================
对二维数组进行转置:
[[1 4 7]
[2 5 8]
[3 6 9]]
使用大写T也可以完成转置:
[[1 4 7]
[2 5 8]
[3 6 9]]
对原数组无影响:
[[1 2 3]
[4 5 6]
[7 8 9]]
ravel()方法 —— 降维
有时候,我们需要将多维数组降维成一维数组,这时我们可以利用ravel()方法来完成这个功能,示例代码如下。同样地,ravel()返回的仅仅是原始数组的视图而已,原始数组本身并没有发生变化。
print("\n对数组进行降维:\n{}".format(two_dim.ravel()))
print("\n对原数组无影响:\n{}".format(two_dim))
===========================================
对数组进行降维:
[1 2 3 4 5 6 7 8 9]
对原数组无影响:
[[1 2 3]
[4 5 6]
[7 8 9]]
flatten()函数 —— 降维
flatten()函数同样可以完成将多维数组展平成一维数组的操作。不同于ravel()返回的是原始数组的视图,flatten()会重新分配内存,完成一次从原始数据到新内存空间的深拷贝,但原始数组并没有发生任何变化。
print("\n对数组flatten降维:\n{}".format(two_dim.flatten()))
print("\n对原数组无影响:\n{}".format(two_dim))
=============================================
对数组flatten降维:
[1 2 3 4 5 6 7 8 9]
对原数组无影响:
[[1 2 3]
[4 5 6]
[7 8 9]]
shape() —— 显式变形
two_dim.shape = (1, -1)
print("\n对数组进行shape降维:\n{}".format(two_dim))
==============================
对数组进行shape降维:
[[1 2 3 4 5 6 7 8 9]]
我们重新定义了一个二维数组的形状,等号右边是一个元组,元组中第一个元素“1”,表明新的数组形状是“1行”的,第二个元素“-1”表示列数由系统自动推导出来,在上述代码中,它就是9,因为元素总数为9,其中一个维度为1,很容易推算出另外的维度信息。
对于N维数组,当N-1维尺寸确定后,用“-1”标记剩余维度,表示让系统推算剩余维度尺寸,这种做法在高维数组操作中(如深度学习框架TensorFlow)很常用,因此该技巧值得掌握。