1、numpy是什么
Python语言一开始并不是设计为科学计算使用的语言,随着越来越多的人发现Python的易用性,逐渐出现了关于Python的大量外部扩展,NumPy (Numeric Python)就是其中之一。NumPy提供了大量的数值编程工具,可以方便地处理向量、矩阵等运算,极大地便利了人们在科学计算方面的工作。另一方面,Python是免费,相比于花费高额的费用使用Matlab,NumPy的出现使Python得到了更多人的青睐。
# 查看numpy的版本 1 import numpy as np2 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)20int32
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 /= 22 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)
[[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14] [15 16 17 18 19]] [[ 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)
[[ 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. ][[ 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]) #访问格式14 print (m[0,1]) #访问格式2
[[ 1. 2.] [ 3. 5.]]2.02.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] = 11113 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]]**************************[[ 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.nan3 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]]