NumPy 是 Python 的一个扩充程序库,支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。内部解除了 Python 的 PIL (全局解释器锁),同时使用 C/C++ 做扩展,运算效率极好,是大量机器学习框架的基础库。
常用操作
数组操作
#----- 初始化,分别初始化为1、0、顺序、随机数
np.array([0, 1, 2, 3, 4])
np.ones(3)
np.zeros(3)
np.arange(5)
np.arange(0, 5)
np.random.random(3)
#----- 计算,可以是等维的数组,也可以是标量
np.ones(3) + np.zeros(3)
np.ones(3) * 10.
#----- 切片操作,与Python的切片基本类似,序号从0开始
data = np.arange(5)
data[0:2]
data[1:]
#----- 聚合函数,包括了min max sum mean std(标准差)
data.max()
矩阵操作
#----- 初始化,可以用数组或者函数初始化,大小为3行*2列
np.array([[1, 2], [3, 4], [5, 6]])
np.ones((3, 2))
np.zeros((3, 2))
np.random.random((3, 2))
#----- 计算,同维的可以直接执行四则运算,可能会执行广播规则
np.ones((3, 2)) + 2 * np.ones((3, 1))
------ 也可以是矩阵乘法,需要严格确保纬度满足要求,如下两种方式相同
a = np.array([1, 2, 3])
b = np.array([[1, 2], [3, 4], [5, 6]])
np.dot(a, b)
a.dot(b)
#----- 切片操作,与数组相似,只是多了几个纬度而已
data = np.ones((3, 2))
data[0, 1]
data[1:3] # 两个纬度都是1:3
data[0:2, 0]
#----- 聚合函数,可以指定具体的纬度
data.max(axis=0)
linalg
在 Numpy 中的 linalg
模块包含了线性代数相关的函数,可以用来计算逆矩阵、特征值、线性方程组以及行列式等。
逆矩阵
需要保证矩阵是方阵且可逆,否则会抛出 LinAlgError
异常。
>>> a = np.mat([[4, 7], [2, 6]])
>>> b = np.linalg.inv(a)
>>> b * a
最后可以通过 b * a
验证结果是否为单位矩阵。
线性方程组
可以求解如 $Ax = b$ 的线性方程组。
>>> A = np.mat([[1, -2, 1], [0, 2, -8], [-4, 5, 9]])
>>> b = np.array([0, 8, -9])
>>> x = np.linalg.solve(A, b)
>>> np.dot(A, x)
其它
array VS. mat
在生成矩阵时,要求的格式不同,其中 array()
只能使用列表,而 mat()
可以使用字符串表示 (可以通过分号 ;
或者逗号 ,
分割)。
>>> a = np.mat("1 2; 3 4")
>>> b = np.mat([[1, 2], [3, 4]])
>>> c = np.array([[1, 2], [3, 4]])
当然,生成的类型也不同,分别是 matix
以及 array
。
另外,比较关键的是计算矩阵的乘法,除了线性代数中严格的乘法定义,numpy
还支持对应位的乘积,也就是函数 multiply()
,两者的 默认行为 是不同的。
mat()
矩阵乘积可以使用星号*
或.dot()
计算,对应位相乘则需要显示调用multiply()
。array()
中的星号*
与multiply()
相同,计算矩阵乘积需要显示调用.dot()
。
使用如上创建的矩阵,对应的结果如下。
>>> np.multiply(a, b)
matrix([[ 1, 4],
[ 9, 16]])
>>> a*b
matrix([[ 7, 10],
[15, 22]])
>>> a.dot(b)
matrix([[ 7, 10],
[15, 22]])
NDArray
这是一个多维数组对象,该对象由 实际数据
和 元数据
组成,其中大部分操作仅仅修改元数据部分,而不改变底层的实际数据。注意,实际的数据必须要保证是同质的,也就是类型相同。
所谓的多维数组,常见的,如向量 (Vector) 是一维,矩阵 (Matrix) 是二维,张量 (Tensor) 是三维,每个维度都会对应一个坐标轴,如下是一个示例。
>>> a = np.reshape(np.array(range(24)), [2, 3, 4])
>>> a
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
对于上述的数组,可以理解成从外向内的维度一次是 2、3、4 。
axis
在 numpy 中的很多函数可以对多维数组进行统计,常见的有 sum()
mean()
var()
std()
,下面以 sum()
函数为例,介绍其中的 axis
参数的含义。
对于 sum()
函数,官方的文档解释为 Sum of array elements over a give dimension. It returns an array with the same shape as input, with the specified dimension removed.
,也就是对指定维度求和,返回的结果只是少了 axis 那一个维度。
仍以上述示例为例。
>>> np.sum(a, axis=0) # (2, 3, 4) --> (3, 4)
array([[12, 14, 16, 18],
[20, 22, 24, 26],
[28, 30, 32, 34]])
>>> np.sum(a, axis=1) # (2, 3, 4) --> (2, 4)
array([[12, 15, 18, 21],
[48, 51, 54, 57]])
>>> np.sum(a, axis=2) # (2, 3, 4) --> (2, 3)
array([[ 6, 22, 38],
[54, 70, 86]])
注意,上述的 np.sum(a, axis=2)
与 np.sum(a, axis=-1)
是等价的。
常见操作
import numpy as np
#----- 多维可以通过shape属性查看维度
arr.shape
#----- 修改维度
arr.shape = 3, 2
arr = arr.reshape(3, 2)
#----- 数组展开,前者只是展示格式不同,而后者会申请内存
arr.ravel()
arr.flatten()
#----- 转置矩阵
arr = np.arange(6).reshape(2, 3)
arr.transpose()
#----- 其它
arr = np.arange(6).reshape(2, 3)
arr.dtype # 类型
arr.shape # 维度(行, 列)
arr.ndim # 行
arr.size # 总大小,也就是 行*列
arr.itemsize # 单个元素的大小
arr.data # 真正的数据信息,包括地址、元素个数等
广播规则
注意,执行 Broadcast 的前提在于,两个矩阵执行的位运算,而非矩阵乘法运算 np.dot(A, B)
,后者相对来说会更加严格。
最简单的示例如下,两者等价,其中后者用到了广播规则。
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> a * b
array([ 2., 4., 6.])
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2., 4., 6.])
简单来说,在执行运算时,需要满足:
- 当前维度的值相等 (行、列都相同);
- 当前维度的值有一个是 1 (另外一个相同)。
测试示例如下。
a = np.array([
[ 0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
b = np.array([1, 2, 3])
#b = np.array([1, 2, 3, 4]) 会报错
#ValueError: operands could not be broadcast together with shapes (4,3) (4,)
print(a + b)
另外的形式与上类似。
a = np.array([
[ 0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
b = np.array([1, 2, 3, 4]).reshape(4, 1)
#b = np.array([1, 2, 3]).reshape(3, 1) 会报错
#ValueError: operands could not be broadcast together with shapes (4,3) (3,1)
print(a + b)
随机数
这一模块用于生成随机数,包含了一系列的函数。
rand()
numpy.random.rand(d0, d1, ..., dn)
生成范围是 [0, 1)
的数据,数据是均匀分布,其中 dN
代表了维度,例如 rand(4, 2)
生成 4 行 2 列的数据。
randn()
numpy.random.randn(d0, d1, ..., dn)
与 rand()
函数类似,只是生成的为正态分布。
uniform()
numpy.random.uniform(low=0.0, high=1.0, size=None)
用于生成均匀分布 (uniform distribution) 的随机数,其中 size
可以是数值或者元组。
RandomState VS. Seed
为了保证实验结果可以复现,尤其是一些示例代码,可以对一些随机数据加入可重复的特性,一般包括了两种方法,全局的还有独立的。
所谓全局,就是通过 np.random.seed()
函数设置一个种子,那么后续生成的随机值基本固定。
import numpy as np
for i in range(4):
np.random.seed(0)
print(np.random.rand(10))
但这样会影响到所有全局随机函数,如果想只对部分函数生效,那么就可以使用如下方法。
import numpy as np
for i in range(4):
rnd = np.random.RandomState(1)
print(rnd.rand(10))
对于 RandomState()
函数来说,其入参可以是 int
array
None
,与 seed()
函数类似,其中 RandomState()
是线程安全的,相比来说更为复杂,可以替换 rand()
函数。
正态随机值
numpy.random.normal(loc=0.0, scale=1.0, size=None)
生成一个符合正态分布的随机序列,详细可以参考 docs.scipy.org 中的介绍。
import numpy
import matplotlib.pyplot as plt
mean = 0
sigma = 1
arr = numpy.random.normal(mean, sigma, size=1000)
abs(mean - np.mean(s)) < 0.01
abs(sigma - np.std(s, ddof = 1)) < 0.01
plt.plot(arr)
plt.show()
常用技巧
linspace()
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
在指定的范围内生成间隔均匀的数字,开始值、终值和元素个数创建表示等差数列的一维数组,可以通过 endpoint 参数指定是否包含终值,默认值为 True,即包含终值。
与之类似的是 arange()
函数,不过该函数不含终止值。
meshgrid()
简单来说,就是生成网格,最常用的是将在两个坐标轴上的点在平面上画网格,如下是一个简单的示例:
import numpy as np
import matplotlib.pyplot as plt
X, Y = np.meshgrid(np.linspace(0, 1, 5), np.linspace(0, 1, 3))
plt.plot(X, Y, marker='.', color='blue', linestyle='none')
plt.show()
这在很多的示例中会使用,后面再详细介绍。
histogram()
用来统计一个数组的直方库,也可以使用 plt.hit()
函数直接绘制一个图。
import numpy as np
import matplotlib.pyplot as plt
arr = np.array([22, 87, 5, 43, 56, 73, 55, 54, 11, 20, 51, 5, 79, 31, 27])
hist, bins = np.histogram(arr, bins = [0, 20, 40, 60, 80, 100])
plt.hist(arr, bins = [0, 20, 40, 60, 80, 100])
plt.title("histogram")
plt.show()
cumsum()
cumsum()
函数用于计算累加,可以有如下的几种方式。
import numpy as np
# 1 2
# 2 3
a = np.cumsum([[1, 2], [2, 3]])
print(a) #[1 3 5 8] 由前面的值依次累加
b = np.cumsum([[1, 2], [2, 3]], axis=0)
print(b) # [[1 2] [3 5]] 每列累加
c = np.cumsum([[1,2],[2,3]],axis=1)
print(c) # [[1 3] [2 5]] 每行累加
参考
- Numpy Broadcasting 关于 Numpy 中的 Broadcasting 的相关介绍。