python基础篇之Numpy
1、numpy是什么
Python语言一开始并不是设计为科学计算使用的语言,随着越来越多的人发现Python的易用性,逐渐出现了关于Python的大量外部扩展,NumPy (Numeric Python)就是其中之一。NumPy提供了大量的数值编程工具,可以方便地处理向量、矩阵等运算,极大地便利了人们在科学计算方面的工作。另一方面,Python是免费,相比于花费高额的费用使用Matlab,NumPy的出现使Python得到了更多人的青睐。
# 查看numpy的版本
1 import numpy as np
2 np.version.full_version
'1.13.1'
我们使用了"import"命令导入了NumPy,并使用numpy.version.full_version查出使用的NumPy版本为1.13.1。在后面的介绍中,我们将大量使用NumPy中的函数,每次都添加numpy在函数前作为前缀比较费劲,则我们引入了外部扩展模块时的小技巧,可以使用"from numpy import *"解决这一问题。
那么问题解决了?慢!Python的外部扩展成千上万,在使用中很可能会import好几个外部扩展模块,如果某个模块包含的属性和方法与另一个模块同名,就必须使用import module来避免名字的冲突。即所谓的名字空间(namespace)混淆了,所以这前缀最好还是带上。
那有没有简单的办法呢?有的,我们可以在import扩展模块时添加模块在程序中的别名,调用时就不必写成全名了,例如,我们使用"np"作为别名并调用version.full_version函数
2、numpy的对象:数组
NumPy中的基本对象是同类型的多维数组(homogeneous multidimensional array),这和C++中的数组是一致的,例如字符型和数值型就不可共存于同一个数组中。例如:
# 生成一个步长为1,长度为20的数组
1 a = np.arange(20)
2 print (a)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
# 查看a类型
1 type(a)
numpy.ndarray
# 重造数组,用reshape函数
1 b = a.reshape(4,5) #将a重造成一个4行5列的二维数组
2 print (b)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
# 高维数组
1 c = a.reshape(2,2,5)
2 print (c)
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]]
[[10 11 12 13 14]
[15 16 17 18 19]]]
1 print (c.ndim) #查看维度
2 print (c.shape) #查看各维度的大小
3 print (c.size) #查看全部元素个数
4 print (c.dtype) #查看元素类型
3
(2, 2, 5)
20
int32
3、创建数组
数组的创建可通过转换列表实现,高维数组可通过转换嵌套列表实现:
# 一维数组
1 raw1 = [0,1,2,3,4]
2 d = np.array(raw1)
3 print ('d:',d)
# 二维数组
4 raw2 = [[0,1,2,3,4], [5,6,7,8,9]]
5 e = np.array(raw2)
6 print ('e:\n',e)
d: [0 1 2 3 4]
e:
[[0 1 2 3 4]
[5 6 7 8 9]]
一些特殊的数组有特别定制的命令生成,如4*5的全零矩阵:
1 f = (4, 5)
2 np.zeros(f) #创建4行5列的二维数组,元素为0,元素默认是double类型,可以增加参数dtype进行修改
3 g = (4, 5)
4 np.ones(g, dtype=int)#创建4行5列的二维数组,元素为1,元素设定为int类型
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
[0, 1)区间的随机数数组:
np.random.rand(5) #产生[0,1)区间的随机数数组
array([ 0.02780353, 0.37508253, 0.15662949, 0.28544584, 0.1020863 ])
4、数组操作之四则运算
简单的四则运算已经重载过了,全部的’+’,’-’,’*’,’/'运算都是基于全部的数组元素的,以加法为例:
1 a = np.array([[1.0, 2], [2, 4]])
2 print ("a:")
3 print (a)
4 b = np.array([[3.2, 1.5], [2.5, 4]])
5 print ("b:")
6 print (b)
7 print ("a+b:")
8 print (a+b)
a:
[[ 1. 2.]
[ 2. 4.]]
b:
[[ 3.2 1.5]
[ 2.5 4. ]]
a+b:
[[ 4.2 3.5]
[ 4.5 8. ]]
这里可以发现,a中虽然仅有一个与元素是浮点数,其余均为整数,在处理中Python会自动将整数转换为浮点数(因为数组是同质的),并且,两个二维数组相加要求各维度大小相同。当然,NumPy里这些运算符也可以对标量和数组操作,结果是数组的全部元素对应这个标量进行运算,还是一个数组:
1 print ("3 * a:")
2 print (3 * a)
3 print ("b + 1.8:")
4 print (b + 1.8)
3 * a:
[[ 3. 6.]
[ 6. 12.]]
b + 1.8:
[[ 5. 3.3]
[ 4.3 5.8]]
类似C++,’+=’、’-=’、’*=’、’/='操作符在NumPy中同样支持:
1 a /= 2
2 print (a)
[[ 0.5 1. ]
[ 1. 2. ]]
开根号求指数也很容易:
1 print ("np.exp(a):")
2 print (np.exp(a)) #指数
3 print ("np.sqrt(a):")
4 print (np.sqrt(a)) #开方
5 print ("np.square(a):")
6 print (np.square(a)) #平方
7 print ("np.power(a, 3):")
8 print (np.power(a, 3)) #三次方
np.exp(a):
[[ 2.71828183 7.3890561 ]
[ 7.3890561 54.59815003]]
np.sqrt(a):
[[ 1. 1.41421356]
[ 1.41421356 2. ]]
np.square(a):
[[ 1. 4.]
[ 4. 16.]]
np.power(a, 3):
[[ 1. 8.]
[ 8. 64.]]
需要知道二维数组的最大最小值怎么办?想计算全部元素的和、按行求和、按列求和怎么办?for循环吗?不,NumPy的ndarray类已经做好函数了:
1 i = np.arange(20).reshape(4,5)
2 print ("i:")
3 print (i)
4 print ("sum of all elements in i: " + str(i.sum())) #求和
5 print ("maximum element in i: " + str(i.max())) #最大值
6 print ("minimum element in i: " + str(i.min())) #最小值
7 print ("maximum element in each row of i: " + str(i.max(axis=1))) #每行的最大值
8 print ("minimum element in each column of i: " + str(i.min(axis=0))) #每列的最小值
i:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
sum of all elements in i: 190
maximum element in i: 19
minimum element in i: 0
maximum element in each row of i: [ 4 9 14 19]
minimum element in each column of i: [0 1 2 3 4]
科学计算中大量使用到矩阵运算,除了数组,NumPy同时提供了矩阵对象(matrix)。矩阵对象和数组的主要有两点差别:一是矩阵是二维的,而数组的可以是任意正整数维;二是矩阵的’*‘操作符进行的是矩阵乘法,乘号左侧的矩阵列和乘号右侧的矩阵行要相等,而在数组中’*'操作符进行的是每一元素的对应相乘,乘号两侧的数组每一维大小需要一致。数组可以通过asmatrix或者mat转换为矩阵,或者直接生成也可以:
1 j = np.arange(20).reshape(4,5) #二维数组
2 j = np.asmatrix(j) #转化成矩阵
3 print (type(j))
4 print (j)
5
6 k = np.matrix('1.0 2.0; 3.0 4.0') #创建矩阵
7 print (type(k))
8 print (k)
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 1. 2.]
[ 3. 4.]]
再来看一下矩阵的乘法,这使用arange生成另一个矩阵b,arange函数还可以通过arange(起始,终止,步长)的方式调用生成等差数列,注意含头不含尾。
1 k = np.arange(2,45,3).reshape(3,5) #arange指的是步长,表示在2到45之间每3各取一个数
2 k = np.mat(k)
3 print (type(k))
4 print (k)
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 2 5 8 11 14]
[17 20 23 26 29]
[32 35 38 41 44]]
有人要问了,arange指定的是步长,如果想指定生成的一维数组的长度怎么办?好办,"linspace"就可以做到:
1 l = np.linspace(0,1,9) # linspace表示在0到1之间一共取9个数
2 print (l)
3 m = l.reshape(3,3)
4 m = np.asmatrix(m)
5 print (type(m))
6 print (m)
[ 0. 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1. ]
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 0. 0.125 0.25 ]
[ 0.375 0.5 0.625]
[ 0.75 0.875 1. ]]
5、数组元素访问
数组和矩阵元素的访问可通过下标进行,以下均以二维数组(或矩阵)为例:
1 m = np.array([[1.0,2],[3.0,5]])
2 print (m)
3 print (m[0][1]) #访问格式1
4 print (m[0,1]) #访问格式2
[[ 1. 2.]
[ 3. 5.]]
2.0
2.0
1 # 赋值实例
2 o = m #这样赋值后对m进行重新赋值,发现o也发生了变化,这是因为Python不是真正将m复制一份给o,而是将o指到了m对应数据的内存地址上,
3 m[0,1] = 999
4 print ('m:')
5 print (m)
6 print ('o:')
7 print (o)
8 print ()
9 print ("*******************")
10 print ()
11 p = m.copy() #若要想赋值,并且不想出现上述情形,可以用copy函数来完成
12 m[0,1] = 111
13 print ('m:')
14 print (m)
15 print ('p:')
16 print (p)
m: [[ 1. 999.] [ 3. 5.]] o: [[ 1. 999.] [ 3. 5.]] ******************* m: [[ 1. 111.] [ 3. 5.]] p: [[ 1. 999.] [ 3. 5.]]
访问某一列或者某一行的数据,用“:”符号。
1 q = np.arange(20).reshape(4,5)
2 print (q)
3 print ()
4 print ("the 1st and 3rd column of q:")
5 print (q[:,(1,3)])
6 print ()
7 print ("the 2nd row of q:")
8 print (q[2,:])
9 print ()
10 print ("将第一列大于5的元素(10和15)对应的第三列元素(12和17)取出来:")#更复杂情形
11 print (q[:,2][q[:,0]>5])
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
the 1st and 3rd column of q:
[[ 1 3]
[ 6 8]
[11 13]
[16 18]]
the 2nd row of q:
[10 11 12 13 14]
将第一列大于5的元素(10和15)对应的第三列元素(12和17)取出来:
[12 17]
可使用where函数查找特定值在数组中的位置:
1 r = np.where(q ==18)
2 print (r)
(array([3], dtype=int64), array([3], dtype=int64))
6、数组操作之矩阵
还是拿矩阵(或二维数组)作为例子:
# 矩阵的转置
1 s = np.random.rand(3,4) #创建3行4列的二维数组
2 print (s)
3 print ("数组的转置:")
4 s_t = np.transpose(s)
5 print (s_t)
6 print ("**************************")
7 t = np.mat(s) #转换成矩阵类型
8 print (type(t))
9 print (t)
10 print ("矩阵的转置:")
11 print (t.T)
[[ 0.63939104 0.4267525 0.711497 0.23821614]
[ 0.78402388 0.16975021 0.63667862 0.70169351]
[ 0.46436988 0.76405254 0.46564003 0.94176015]]
数组的转置:
[[ 0.63939104 0.78402388 0.46436988]
[ 0.4267525 0.16975021 0.76405254]
[ 0.711497 0.63667862 0.46564003]
[ 0.23821614 0.70169351 0.94176015]]
**************************
<class 'numpy.matrixlib.defmatrix.matrix'>
[[ 0.63939104 0.4267525 0.711497 0.23821614]
[ 0.78402388 0.16975021 0.63667862 0.70169351]
[ 0.46436988 0.76405254 0.46564003 0.94176015]]
矩阵的转置:
[[ 0.63939104 0.78402388 0.46436988]
[ 0.4267525 0.16975021 0.76405254]
[ 0.711497 0.63667862 0.46564003]
[ 0.23821614 0.70169351 0.94176015]]
# 矩阵的求逆
1 import numpy.linalg as nlg
2 u = np.random.rand(2,2)
3 u = np.mat(u)
4 print ("u:")
5 print (u)
6 u_1 = nlg.inv(u)
7 print ("u_1:")
8 print (u_1)
9 print ()
10 print ("乘积为单位矩阵来验证:")
11 print (u * u_1)
u:
[[ 0.75373943 0.53785259]
[ 0.31554461 0.21885755]]
u_1:
[[ -46.02762626 113.11502707]
[ 66.36174467 -158.5178845 ]]
乘积为单位矩阵来验证:
[[ 1.00000000e+00 0.00000000e+00]
[ -1.77635684e-15 1.00000000e+00]]
# 求特征值和特征向量
1 v = np.random.rand(3,3)
2 eig_value,eig_vector = nlg.eig(v)
3 print ("eig_value:")
4 print (eig_value)
5 print ("eig_vector:")
6 print (eig_vector)
eig_value:
[ 1.00780791+0.j -0.20549578+0.18720574j -0.20549578-0.18720574j]
eig_vector:
[[ 0.40202136+0.j -0.37400209+0.38405454j -0.37400209-0.38405454j]
[ 0.70752764+0.j -0.00198203-0.36678799j -0.00198203+0.36678799j]
[ 0.58119142+0.j 0.76032046+0.j 0.76032046-0.j ]]
# 按列拼接
1 w = np.array([1,2,3])
2 x = np.array([4,5,6])
3 print (np.column_stack((w,x)))
4 print ()
5 # 还可以用hstack或者vstack来拼接
6 y = np.random.rand(2,2)
7 z = np.random.rand(2,2)
8 print ("y:")
9 print (y)
10 print ("z:")
11 print (z)
12 a = np.hstack([y,z])
13 b = np.vstack([y,z])
14 print ("a:")
15 print (a)
16 print ("b:")
17 print (b)
7、缺失值
1 c = np.random.rand(2,2)
2 c[0, 1] = np.nan
3 print (np.isnan(c))
4 print (np.nan_to_num(c)) #nan_to_num可用来将nan替换成0
[[False True]
[False False]]
[[ 0.71645542 0. ]
[ 0.59114199 0.19739796]]