numpy 是第三方模块,如果我们想使用它,必须先安装上该模块。安装方法: pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy。
numpy 模块内有很多类库,这些类库里面实现了存储数据的属性和对数据进行运算的函数。其实 numpy 模块里面的类和我们 python 内置的 list 一样,都是对数据进行存储和运算的类,只是 numpy 模块里面的类要比 list 要丰富的多,现在开始我们就来学习 numpy 的主要 API。
numpy 是一个模块,它主要功能是做数据处理,既然是做数据处理,首先要有数据存储的功能,numpy 给我们提供一个 ndarray 类可以存储要处理的数据。
ndarray 类是 numpy 创造的一个数据类型,在使用之前,我们首先想到的是如何初始化它。numpy 的 array 函数负责初始化 numpy 的数据,我们可以给该函数传入用 list 或 tuple 进行初始化。
import numpy as np nparr = np.array((2, 3, 4)) # 可以用 tuple 来创建 ndarray 对象 print(nparr) print(type(nparr)) nparr = np.array([2, 3, 4]) # 可以用 list 来创建 ndarray 对象 print(nparr) print(type(nparr))
上面代码中,我们发现 ndarray 类型的数据和 list 很像,ndarray 和 list 对象相比,ndarray 数据的成员之间只是没有用逗号隔开。
运行结果如下:
[2 3 4] <class 'numpy.ndarray'> [2 3 4] <class 'numpy.ndarray'>
我们也可以使用 numpy 提供的 arange 函数对 numpy 进行初始化,或者使用 ndarray 对象本身初始化。
import numpy as np nparr = np.arange(0, 10) # 用np提供的arange函数 print(nparr) print(type(nparr)) nparr2 = np.array(nparr) # 用nparr对象本身 print(nparr2) print(type(nparr2))
运行结果如下:
[0 1 2 3 4 5 6 7 8 9] <class 'numpy.ndarray'> [0 1 2 3 4 5 6 7 8 9] <class 'numpy.ndarray'>
numpy 支持切片功能,切片规则和 list 一样。通过切片取得的结果同样为 ndarray 类型。
import numpy as np nparr = np.arange(0, 10) print(nparr[:4]) print(nparr[3: 7]) print(nparr[:7: 2])
运行结果如下:
[0 1 2 3] [3 4 5 6] [0 2 4 6]
numpy 提供的运算函数的效率比其它数据结构提供的运算函数高效(比如 list 等等)。下面的案例中,我们分别创建一个 ndarray 类型的对象和 list 类型的对象,对象中存储的数据的内容都是一样的,存储了 0-9999999 的整数,然后我们对使用 numpy 提供的 sum 函数和 list 提供的 sum 函数对这些数据求和运算,我们发现 numpy 要比 list 快得多。
import time import numpy as np nparr = np.array(np.arange(10000000)) # [0 1 2 ...10000000 - 1] bgtime = time.time() nparr.sum() # 对numpy中的所有数据求和 endtime = time.time() print("numpy计算耗时:", endtime - bgtime) mylist = range(10000000) # [0, 1, 2 ...10000000 - 1] bgtime = time.time() sum(mylist) # 对list中的所有数据求和 endtime = time.time() print("list计算耗时", endtime - bgtime)
运行结果如下:
numpy计算耗时: 0.006000518798828125 list计算耗时 0.711040735244751
我们有时候需要把复杂的数据结构转为我们常用的数据结构,方便我们的使用,numpy 提供了 tolist 函数,可以把 ndarray 类型的数据转为list类型的数据。
import numpy as np nparr = np.arange(0, 10) print(nparr) larr = nparr.tolist() print(larr)
运行结果如下:
[0 1 2 3 4 5 6 7 8 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numpy 和 list 一样支持下标访问里面的元素,同样下标是从零开始计算。
import numpy as np nparr = np.array(0, 10) print(nparr[2])
运行结果如下:
2
numpy 的 ndarray 对象可以进行四则运算。注意:进行四则运算的数组元素个数必须一致。
import numpy as np npdata_one = np.array([1, 2, 3]) npdata_two = np.array([4, 5, 6]) print("相加结果:", npdata_one + npdata_two) print("相减结果:", npdata_one - npdata_two) print("相乘加结果:", npdata_one * npdata_two) print("相除加结果:", npdata_one / npdata_two)
上面代码中我们分别定义两个 ndarray 对象,对象为一维数组,在 tensorflow 或者数学概念上一维数组表示向量,这两个向量的 shape为(3,),表示 1 维度含 3 个元素。然后对其进行四则运算。
运行结果如下:
相加结果: [5 7 9] 相减结果: [-3 -3 -3] 相乘加结果: [ 4 10 18] 相除加结果: [0.25 0.4 0.5 ]
numpy 还提供其它常用的科学计算函数,比如有求均值,求方差,找最大值和最小值以及生成随机数等等。
import numpy as np nparr = np.arange(0, 10) print("均值:", nparr.mean()) # 求取均值 print("方差:", nparr.std()) # 求方差 print("最小值:", nparr.min()) # 找出最小值 print("最大值:", nparr.max()) # 找出最大值 print(np.random.rand(5)) # 生成5个随机数
上面代码中我们定义一个一维数组(向量)。
运行结果如下:
均值: 4.5 方差: 2.8722813232690143 最小值: 0 最大值: 9 [0.54464551 0.61172934 0.91811861 0.93888077 0.23287131]
当然我们也可以对二维数组(矩阵)或者多维数组(标量)做相应的科学计算,向量和矩阵数据计算在人工智能的数据使用中非常常见。
前面我们一直都在学习 numpy 的一维数组(向量)相关的定义和函数以及应用,下面我们就来学习关于 numpy 多维数组的定义和使用。
numpy 的多维数组初始化方法和一维数组初始化方法一样,我们常用使用 list 或 tuple 的多维数组对 numpy 进行初始化。下面我们定义一个 2 行 3 列的多维数组(矩阵),然后打印出结果。
import numpy as np nparrs = np.array([[2, 3, 4], [5, 6, 7]]) # 创建2行3列的多维数组(矩阵) print("数据:", nparrs) print("维度:", nparrs.shape) # (2, 3) print("类型", type(nparrs))
运行结果如下:
数据: [[2 3 4] [5 6 7]] 维度: (2, 3) 类型 <class 'numpy.ndarray'>
numpy 数组可以进行维度变换,可以把多维数组展平成一维数组,numpy 提供的 ravel 函数可以完成多数组展平为一维数组的功能,当然也可以对一维数组本身展平为一维数组(这没什么意义)。
import numpy as np nparrs = np.array([[2, 3, 4], [5, 6, 7]]) # 创建2行3列的多维数组(矩阵) nparr = nparrs.ravel() # 对多维数组进行展平成一位数组,赋值给nparr print("展平后的值:", nparr) print("原本的值不变:", nparrs) # 注意nparrs本身的值不会变
运行结果如下:
展平后的值: [2 3 4 5 6 7] 原本的值不变: [[2 3 4] [5 6 7]]
注意:ravel 不改变被展平数组本身,它会把展平后的一维数组作为一个结果返回。
numpy 还提供一个 reshape 函数,该函数可以变换数组的维度,也就是说它可以把高维数组转为低维度数组,同样也可以把低维度数组转为高纬度数组。
import numpy as np nparra = np.arange(8) # 定义一个一维数组(向量) print("一维数组:", nparra) nparrb = nparra.reshape(2, 4) # 把一维数组转为二维数组(矩阵) print("改变维度后的二维数组:", nparrb) print("被改变数组本身的维度不变:", nparra) nparrc = nparrb.reshape(8) # 把二维数组转为一维数组(向量) print("一维数组:", nparrc) print("被改变数组本身的维度不变:", nparrb)
运行结果如下:
一维数组: [0 1 2 3 4 5 6 7] 改变维度后的二维数组: [[0 1 2 3] [4 5 6 7]] 被改变数组本身的维度不变: [0 1 2 3 4 5 6 7] 一维数组: [0 1 2 3 4 5 6 7] 被改变数组本身的维度不变: [[0 1 2 3] [4 5 6 7]]
注意:reshape 函数同样不会改变被转为数组本身,它和 ravel 函数一样会返回新的结果。
numpy 提供 shape 函数不但可以随意变换数组的维度(高纬度和低纬度互相转换),它也改变数组本身。
import numpy as np nparr = np.arange(8) # 定义一个1维数组(向量) nparr.shape = (2, 4) # 把nparr本身转为2行4列的2维数组(矩阵) print("改变本身:", nparr) nparr.shape = (8,) # 把nparr本身转为1维数组(向量) print("改变本身:", nparr)
运行结果如下:
改变本身: [[0 1 2 3] [4 5 6 7]] 改变本身: [0 1 2 3 4 5 6 7]
同样 numpy 的多维数组也支持四则运算,下面我们定义两个二维数组(矩阵),然后对其做四则运算,注意:numpy 的二维数组(矩阵)同样必须符合数学上的运算规则。
import numpy as np nparra = np.array([[2, 3], [4, 5]]) nparrb = np.array([[3, 4], [5, 6]]) print("矩阵相加:", nparra + nparrb) print("矩阵相减:", nparra - nparrb) print("矩阵相乘:", nparra * nparrb) print("矩阵相除:", nparra / nparrb)
运行结果如下:
矩阵相加: [[ 5 7] [ 9 11]] 矩阵相减: [[-1 -1] [-1 -1]] 矩阵相乘: [[ 6 12] [20 30]] 矩阵相除: [[0.66666667 0.75 ] [0.8 0.83333333]]
我们知道二维数组在数学上代表矩阵,我们知道矩阵支持叉乘运算。下面我们定义两个二维数组(矩阵),分别为 1 行 2 列和 2 行 3 列,根据矩阵叉乘规则,叉乘结果为 1 行 3 列的矩阵。
import numpy as np nparra = np.array([[1, 2]]) # (1, 2) nparrb = np.array([[1, 2, 3], # (2, 3) [4, 5, 6]]) data = np.matmul(nparra, nparrb) print("矩阵叉乘:", data)
运行结果如下:
矩阵叉乘: [[ 9 12 15]]
numpy 的 hstack 函数可以对数组进行水平组合,注意:被水平组合的两个数组的行数必须相同。
import numpy as np nparra = np.array([[1, 2], [3, 4]]) nparrb = np.array([[4, 5, 6], [7, 8, 9]]) print("水平组合:\n", np.hstack((nparra, nparrb)))
运行结果如下:
水平组合: [[1 2 4 5 6] [3 4 7 8 9]]
numpy 的 vstack 函数可以对数组进行垂直组合,注意:被垂直组合的两个数组的列数必须相同。
import numpy as np nparra = np.array([[1, 2, 3]]) nparrb = np.array([[4, 5, 6], [7, 8, 9]]) print("垂直组合:\n", np.vstack((nparra, nparrb)))
运行结果如下:
垂直组合: [[1 2 3] [4 5 6] [7 8 9]]
numpy 的 random.RandomState.rand (维度)函数返回一个 [0, 1) 之间的随机数,维度为空返回一个标量。
import numpy as np rdm = np.random.RandomState(seed=1) # 同一个种子生成的随机数相同 a = rdm.rand() # 维度为0,返回一个标量 b = rdm.rand(2, 3) # 维度为2,返回2行3列的矩阵 print("a:", a) print("b", b)
运行结果如下:
a: 0.417022004702574 b [[7.20324493e-01 1.14374817e-04 3.02332573e-01] [1.46755891e-01 9.23385948e-02 1.86260211e-01]]
注意,区间 [0, 1) 代表左闭右开,也就是生成的随机数可以包含 0 但不能包含 1。
numpy 的 mgrid [起始值:结束值:步长, 起始值:结束值:步长,…]可以生产网格坐标点,该函数经常和 numpy 的 ravel 函数以及 numpy 的 c_[] 一起使用。
numpy 的 c_[数组1,数组2,…]使返回的间隔数值点配对。
import numpy as np x, y = np.mgrid[1: 3: 1, 2: 4: 0.5] print("x:", x) print("y:", y) grid = np.c_[x.ravel(), y.ravel()] # 生成图状数据(网格化数据) print("grid:\n", grid)
运行结果如下:
x: [[1. 1. 1. 1.] [2. 2. 2. 2.]] y: [[2. 2.5 3. 3.5] [2. 2.5 3. 3.5]] grid: [[1. 2. ] [1. 2.5] [1. 3. ] [1. 3.5] [2. 2. ] [2. 2.5] [2. 3. ] [2. 3.5]]
我们的数据经常来自于文件中,numpy 具有读取文件的功能,同样也可以把数据存储到文件中。
numpy 的 loadtxt 函数可以从文件中读取数据,我们有个 nparr.txt 文件,里面存储了 3 行 3 列的数据,我们把该文件中的数据读取到 numpy 中,然后打印出来。
如下图是文件里面存储的内容
import numpy as np data = np.loadtxt('nparr.txt', dtype=int) print(data)
运行结果如下:
[[0 1 2] [3 4 5] [6 7 8]]
如上代码,其中 dtype=int 是说明把文件中读取的内容以整数的形式存储到 numpy 中,否则默认以 float 的形式读取到 numpy 中。
numpy 的 savetxt 函数可以把 numpy 中的数据存储到文件中。
import numpy as np nparr = np.array([[4, 5, 6], [7, 8, 9]]) np.savetxt('nparr.txt', nparr, fmt="%d")
如上代码中,我们定义一个二维数组 nparr,然后把它存储到文件 nparr.txt 中,其中 fmt="%d", 是指把数据以整数类型存储到文件中,否则默认是以 float 类型存储到文件中。
执行代码后,文件里面存储的内容
numpy 还提供 load 和 save 函数同样可以读写文件,只是读写文件的后缀名必须是 npy。大家可以自行使用 load 函数读文件,使用 save 函数写文件做测试,在此不在赘述。
了解numpy的数据结构
熟练使用numpy常用的函数
会使用numpy进行文件读写操作