前言

划水学习一下python科学计算库,提升一些自己的逼格:)

Numpy

Numpy是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表结构要高效的多。

Numpy包括:

一个强大的N维数组对象Array;

比较成熟的(广播)函数库;

用于整合C/C++和Fortran代码的工具包;

使用的线性代数、傅里叶变换和随机数生成函数

Numpy提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库,专为进行严格的数字处理。

安装方法

pip install --user numpy

用法学习

导入numpy

>>> from numpy as np

通过给array函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建多维数组

>>> a = np.array([1, 2, 3, 4])
>>> b = np.array([5, 6, 7, 8])
>>> c = np.array([[1, 2, 3, 4],[4, 5, 6, 7],[7, 8, 9, 10]])
>>> b
array([5, 6, 7, 8])
>>> c
array([[ 1, 2, 3, 4],
[ 4, 5, 6, 7],
[ 7, 8, 9, 10]])
>>> c.dtype
dtype('int64')

数组的大小可以通过其shape属性获得:

>>> a.shape
(4,)
>>> c.shape
(3, 4)

数组元素的存取方法和Python的标准方法相同

>>> a = np.arange(10) # arange函数用于创建等差数组,类似range函数,区别在于arange返回的是一个数据,而range返回的是list。
>>> a[5] # 用整数作为下标可以获取数组中的某个元素
5
>>> a[3:5] # 用范围作为下标获取数组的一个切片,包括a[3]不包括a[5]
array([3, 4])
>>> a[:5] # 省略开始下标,表示从a[0]开始
array([0, 1, 2, 3, 4])
>>> a[:-1] # 下标可以使用负数,表示从数组后往前数
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> a[2:4] = 100,101 # 下标还可以用来修改元素的值
>>> a
array([ 0, 1, 100, 101, 4, 5, 6, 7, 8, 9])
>>> a[1:-1:2] # 范围中的第三个参数表示步长,2表示隔一个元素取一个元素
array([ 1, 101, 5, 7])
>>> a[::-1] # 省略范围的开始下标和结束下标,步长为-1,整个数组头尾颠倒
array([ 9, 8, 7, 6, 5, 4, 101, 100, 1, 0])
>>> a[5:1:-2] # 步长为负数是,开始下标必须大于结束下标
array([ 5, 101])

和Python列表序列不同,通过下标范围获取的新的数组是原始数组的一个视图。它与原始数组共享同一块数据空间:

>>> b = a[3:7] # 通过下标范围产生一个新的数组b,b和a共享同一块数据空间
>>> b
array([101, 4, 5, 6])
>>> b[2] = -10 # 将b的第二个元素修改为-10
>>> b
array([101, 4, -10, 6])
>>> a # a 的第5个元素也被修改为10
array([ 0, 1, 100, 101, 4, -10, 6, 7, 8, 9])

NumPy和Matlab不一样对于多维数组的运算,缺省(默认)情况下并不使用矩阵运算,如果你希望对数组进行矩阵运算的话,可以调用相应的函数。

NumPy库提供了matrix类,使用matrix类创建的是矩阵对象,它们的加减乘除运算缺省(默认)采用矩阵方式计算,因此用法和MatLab十分类似。但是由于NumPy中同时存在ndarray和matrix对象,用户很容易将两者弄混。这有违Python的“显式优于隐式”的原则,因此并不推荐在较复杂的程序中使用matrix。

>>> a = np.matrix([[1, 2, 3],[5, 5, 6],[7, 9, 9]])
>>> a*a**-1
matrix([[ 1.00000000e+00, 0.00000000e+00, -5.55111512e-17],
[ 4.44089210e-16, 1.00000000e+00, 3.33066907e-16],
[ 4.44089210e-16, 0.00000000e+00, 1.00000000e+00]])

因为a是用matrix创建的矩阵对象,因此乘法和幂运算符都变成了矩阵运算,于是上面计算的是矩阵a和其逆矩阵的成绩,结果是一个单位矩阵。

矩阵的乘积可以使用dot函数进行计算。对于二维数组,它计算的是矩阵乘积,对于一维数组,它计算的是点积。当需要将一位数组当做矢量或者行矢量进行矩阵计算时,推荐先使用reshape函数将一位数组转换成二维数组:

>>> a = np.array([1, 2, 3])
>>> a.reshape((-1, 1))
array([[1],
[2],
[3]])
>>> a.reshape((1, -1))
array([[1, 2, 3]])

除了dot计算乘积之外,NumPy还提供了inner和outer等多种计算乘积的函数。这些函数计算乘积的方式不同,尤其是当处理多维数组的时候,更容易搞混。下面分别介绍这几个函数。

dot:对于两个一位的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为“内积”);对于二维数组,计算的是两个数组的矩阵乘积;对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是——数组a的最后一维上的所有元素于数组b的倒数第二位上的所有元素的乘积和。

dot(a, b)[i, j, k, m] = sum(a[i,j,:] * b[(k, :, m)])

下面以两个三维数组的乘积演示一个dot乘积的计算结果。

首先创建两个三维数组,这两个数组的最后两维满足矩阵乘积的条件:

>>> a = np.arange(12).reshape(2, 3, 2)
>>> b = np.arange(12, 24).reshape(2, 2, 3)
>>> c = np.dot(a, b)
>>> a
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]]])
>>> b
array([[[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23]]])
>>> c
array([[[[ 15, 16, 17],
[ 21, 22, 23]],
[[ 69, 74, 79],
[ 99, 104, 109]],
[[123, 132, 141],
[177, 186, 195]]],
[[[177, 190, 203],
[255, 268, 281]],
[[231, 248, 265],
[333, 350, 367]],
[[285, 306, 327],
[411, 432, 453]]]])

dot乘积的结果c可以看作是数组a,b的多个子矩阵的乘积:

>>> np.alltrue(c[0,:,0,:] == np.dot(a[0],b[0]))
True
>>> np.alltrue(c[1,:,0,:] == np.dot(a[1],b[0]))
True
>>> np.alltrue(c[0,:,1,:] == np.dot(a[0],b[1]))
True
>>> np.alltrue(c[1,:,1,:] == np.dot(a[1],b[1]))
True

inner: 和dot乘积一样,对于两个一位数组,计算的是这两个数组对应下标元素的乘积和;对于多维数组,它计算的结果数组中的每个元素都是——数组a和b的最后一维的内积,因此数组a和b的最后一维的长度必须相同。

inner×(a, b)[i, j, k, m] = sum(a[i, j, :]*b[k, m, :])

下面是inner乘积的演示:

>>> a = np.arange(12).reshape(2,3,2)
>>> b = np.arange(12,24).reshape(2,3,2)
>>> c = np.inner(a,b)
>>> a
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]]])
>>> b
array([[[12, 13],
[14, 15],
[16, 17]],
[[18, 19],
[20, 21],
[22, 23]]])
>>> c.reshape(2,3,2,3)
array([[[[ 13, 15, 17],
[ 19, 21, 23]],
[[ 63, 73, 83],
[ 93, 103, 113]],
[[113, 131, 149],
[167, 185, 203]]],
[[[163, 189, 215],
[241, 267, 293]],
[[213, 247, 281],
[315, 349, 383]],
[[263, 305, 347],
[389, 431, 473]]]])
>>> c[0,0,0,0] == np.inner(a[0,0],b[0,0])
True
>>> c[0,1,1,0] == np.inner(a[0,1],b[1,0])
True
>>> c[1,2,1,2] == np.inner(a[1,2],b[1,2])
True

outer:只按照一维数组进行计算,如果传入参数是多维数组,则先将此数组展平为一维数组,之后再进行运算。outer乘积计算的列向量和行向量的矩阵乘积:

>>> np.outer([1,2,3],[4,5,6,7])
array([[ 4, 5, 6, 7],
[ 8, 10, 12, 14],
[12, 15, 18, 21]])

矩阵计算中更高级的一些运算可以在NumPy的线性代数子库linalg中找到。例如inv函数计算逆矩阵,solve函数可以求解一元多次方程组。下面是solve函数的一个例子:

>>> a = np.random.rand(10,10)
>>> b = np.random.rand(10)
>>> x = np.linalg.solve(a,b)
>>> a
array([[ 0.24353531, 0.29659437, 0.28101984, 0.52485836, 0.00183735,
0.30703321, 0.53983274, 0.27464789, 0.73209528, 0.67549256],
[ 0.01559972, 0.92602761, 0.47485384, 0.61468036, 0.37011691,
0.85070726, 0.41072878, 0.10564565, 0.05305942, 0.23846902],
[ 0.94943831, 0.85915453, 0.65884278, 0.64876059, 0.35727861,
0.84109415, 0.33477114, 0.82056791, 0.03162534, 0.39403621],
[ 0.24769378, 0.07308019, 0.29308628, 0.33071024, 0.14306124,
0.86322678, 0.4991317 , 0.96904689, 0.03166429, 0.46169691],
[ 0.30099666, 0.51024363, 0.55342961, 0.27470896, 0.53636676,
0.39594886, 0.29878566, 0.13328393, 0.64219768, 0.30102947],
[ 0.43426324, 0.08116221, 0.20591229, 0.73077177, 0.23106824,
0.51030064, 0.26527246, 0.25208973, 0.45159047, 0.96635508],
[ 0.89780861, 0.34967281, 0.04718447, 0.12239271, 0.21352227,
0.53960624, 0.30945019, 0.85174851, 0.65440119, 0.29891452],
[ 0.98515015, 0.50517941, 0.42574849, 0.29224782, 0.11825866,
0.92779448, 0.64939983, 0.14020983, 0.46421195, 0.3061906 ],
[ 0.30094076, 0.12430322, 0.97022063, 0.69191872, 0.32091803,
0.37656987, 0.30484649, 0.3463515 , 0.43320042, 0.9442171 ],
[ 0.94531206, 0.59132457, 0.81175354, 0.12371409, 0.43948888,
0.54814142, 0.03465268, 0.62540882, 0.16018337, 0.35340181]])
>>> b
array([ 0.96002843, 0.73284286, 0.19247122, 0.83485676, 0.7007295 ,
0.04948528, 0.22721187, 0.83641745, 0.9003207 , 0.43669935])
>>> x
array([-0.77451899, 0.47860311, 0.98693451, -1.35492025, -0.72791704,
0.33877835, 1.11544924, 0.0841362 , 0.34789791, 0.67781082])
>>> np.sum(np.abs(np.dot(a,x) - b))
9.9920072216264089e-16

solve函数有两个参数a和b。a是一个N x N的二维数组,而b是一个长度为N的一维数组,solve函数找到一个长度为N的一维数组x,使得a和x的矩阵乘积正好等于b,数组x就是多元一次方程组的解。