Warning: mysqli_query(): (HY000/1): Can't create/write to file '/tmp/#sql_a75_0.MYI' (Errcode: 28 - No space left on device) in /www/wwwroot/www.soomai.com/wp-includes/wp-db.php on line 2033
嗨,大家好,
今天要来认识处理矩阵运算的好工具- numpy,
网络上说numpy的好用程度堪比matlab,
可以很方便的做矩阵乘法、求矩阵的逆矩阵,
使一些复杂的数学运算成为可能
安装
numpy不是python的内建模组,
可能会需要另外安装。
但如果你是直接安装anaconda 的话,
那numpy也已经装好了,不必再额外安装
基础概念
首先学习如何宣告一个numpy的矩阵,
要得到一个numpy的矩阵很简单,
用np.array把python的list包起来就可以,
以下是实例:import numpy as npList = [[i for i in range(3)] for j in range(4)]A = np.array(List)print(A)
结果:[[0 1 2] [0 1 2] [0 1 2] [0 1 2]]
Matrix 或 ndarray?
在numpy中有两种宣告矩阵的方法:import numpy as npList = [[i for i in range(3)] for j in range(4)]A = np.array(List)print(A)print(type(A))B = np.matrix(List)print(B)print(type(B))
结果:[[0 1 2] [0 1 2] [0 1 2] [0 1 2]][[0 1 2] [0 1 2] [0 1 2] [0 1 2]]
根据官方文件NumPy for Matlab users的建议,
使用ndarray会比较好,
有鉴于此,本文接下来的示范以ndarray为主。
另外这份文件也蛮值得一读的,
整理了各项功能对应的指令
重要概念: numpy的加减乘除是对应位置的加减乘除矩阵 运算 矩阵 = 矩阵相同位置的运算各自做运算
矩阵 运算 常数 = 矩阵每个位置去运算该常数
这是我对numpy概念的统整,
看懂这两句话之后,
numpy的逻辑大致理解八成了,
底下举大量例子辅助说明
一、矩阵 运算 矩阵
譬如说我有两个2*2矩阵A, B,
我要做矩阵加、减法可以直接写A+B,A-B,
但是如果写A*B的话,是直接做对应元素的相乘:
(等一下再说如果真的要做矩阵乘法怎么做)import numpy as npA = np.array([ [1,2], [5,3]])B = np.array([ [6,2], [1,7]])print(A+B)print(A-B)print(A*B)
结果:[[ 7 4] [ 6 10]][[-5 0] [ 4 -4]][[ 6 4] [ 5 21]]
这边A*B就直接得到单纯相同位置相乘的结果:[[ 1*6 2*2] [ 5*1 3*7]]
其实不是只有加减乘除,
任何基础运算都遵循这个规则
譬如说A**B就得到[[ 1**6 2**2] [ 5**1 3**7]]
A^B(^是xor运算)就得到[[ 1^6 2^2] [ 5^1 3^7]]
再类推一下,A==B并非判断两个矩阵是否相等,
A==B会得到什么呢?
答案:import numpy as npA = np.array([ [1,2], [5,3]])B = np.array([ [6,2], [1,7]])print(A==B)
结果:[[False True] [False False]]
答案就是比较相同位置元素的值是否相等。
一开始,我也很不习惯这种设计,
为什么矩阵乘法不直接写A*B呢?不直觉
可是了解之后,我觉得其实这个设计还不错耶~
反而非常单纯,
等于不必去记太多额外的语法,
因为所有运算都遵循这样的规则(真正要记的大概就是矩阵乘法和反矩阵最常用)
二、矩阵 运算 常数
再来看矩阵运算常数的例子,
例如A**3可不是矩阵乘法乘三次的意思,
单纯是每个分量相乘:import numpy as npA = np.array([ [1,2], [5,3]])print(A**3)
结果:[[ 1 8] [125 27]]
类推: 3**A其实就是[[3**1 3**2] [3**5 3**3]]
的意思
懂了的话,你也可以尝试推推看print(A>2), print(1/A)应该会得到什么?
印出答案验证你的猜测
常见矩阵运算
相信透过刚刚的介绍,
你应该了解A*B不是矩阵相乘,
1/A或A ** (-1)也不是A的逆矩阵,
这边要示范真的求矩阵相乘与逆矩阵的语法
矩阵相乘、逆矩阵、转置矩阵、判断矩阵是否相等import numpy as npA = np.array([ [1,2], [5,3]])B = np.array([ [6,2], [1,7]])print(A.dot(B)) # 矩阵相乘print(np.linalg.inv(A)) #求A的反矩阵,若A不可逆会出错print(A.T) # 求A的转置矩阵print(np.array_equal(A,B)) # 判断A, B两个矩阵是否相等
结果:[[ 8 16] [33 31]][[-0.42857143 0.28571429] [ 0.71428571 -0.14285714]][[1 5] [2 3]]False
宣告特殊矩阵
numpy的ones, zero, eye分别可以创建全1矩阵、零矩阵、单位矩阵:import numpy as npONE = np.ones((3,4))O = np.zeros((3,4))I = np.eye(3)print(ONE)print(O)print(I)
结果:[[1. 1. 1. 1.] [1. 1. 1. 1.] [1. 1. 1. 1.]][[0. 0. 0. 0.] [0. 0. 0. 0.] [0. 0. 0. 0.]][[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]]
另外我觉得这两个指令np.arange()和np.linspace()也比较常用,
例子:import numpy as npA = np.arange(5,19,2)B = np.linspace(0,10,7)print(A)print(B)
结果:[ 5. 7.1 9.2 11.3 13.4 15.5 17.6][ 0. 1.66666667 3.33333333 5. 6.66666667 8.33333333 10. ]
若你本来熟悉python基础语法的话,
那么np.arange()的语法跟python原生的range()相当接近,
np.arange(5,19,2)是从5~19(不包含19),步长为2的阵列
np.linspace(0,10,7) 则是得到首项未项是0和10,
总有7项的等差数列
矩阵合并、调整大小
numpy中的hstack方法和vstack分别可以做「水平合并」与「垂直合并」,
实例:import numpy as npA = np.array([ [1,2], [5,3]])B = np.array([ [6,2], [1,7]])print(np.hstack((A,B)))print(np.vstack((A,B)))
结果:[[1 2 6 2] [5 3 1 7]][[1 2] [5 3] [6 2] [1 7]]
reshape语法可以调整矩阵大小,
实例如下:import numpy as npA = np.arange(1,11)print(A)B = np.reshape(A,(2,5)) #或写 A.reshape((2,5))print(B)A[0] = 20print(B)
结果:[ 1 2 3 4 5 6 7 8 9 10][[ 1 2 3 4 5] [ 6 7 8 9 10]][[20 2 3 4 5] [ 6 7 8 9 10]]
这边需注意用reshape产生的矩阵与原矩阵共用记忆体,
若修改A矩阵的值,B矩阵会跟着修改(需留意这个特性,避免日后程序有bug很难找)
若用resize函数则产生的矩阵不共用记忆体
(参考: NumPy 阵列重塑形状和调整大小)
矩阵取子矩阵
这部分若是已经学过python的切片语法的话我觉得就超简单,
语法非常相似,差别在于二维矩阵的切片会用,隔开列、行
实例:import numpy as npA = np.arange(1,21)A.resize((5,4)) print(A)
结果:[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12] [13 14 15 16] [17 18 19 20]]
这时我想要取第二列(row)以后、第二~三行(column)的子矩阵怎么办呢?(最上面叫「第一列」、最左边叫「第一行」)
实例:import numpy as npA = np.arange(1,21)A.resize((5,4)) print(A[1:, 1:3])
结果:[[ 6 7] [10 11] [14 15] [18 19]]
跟python原生的切片语法超像吧?(留给大家自行领悟)
按条件筛选
譬如说我们想返回矩阵A里面大于6的值,
便可以写A[A>6],
实例:import numpy as npA = np.arange(1,21)A.resize((5,4)) print(A[A>6]) # 返回一个一维矩阵
结果:[ 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
其它好用运算- 求和、求积、累积和
另外,numpy还有一些其它好用的运算sum, product, cumsum,
实例 (这边发现numpy跟原生的python相比,可能有溢位问题):import numpy as np"""实例:a 是一个三维阵列,大小2*3*4"""a = [[[1,2,3,2], [1,2,3,1], [2,3,4,1]], [[1,0,2,0], [2,1,2,0], [2,1,1,1]]]"""np.sum()可以指定要沿着哪一个分量相加,例如axis=0就是所有a[i][n1][n2]的总和,i=0,1axis=1就是所有a[n0][i][n2]的总和,i=0,1,2axis=2就是所有a[n0][n1][i]的总和,i=0,1,2,3什么都没指定则会将阵列总和算出。np.prod()效果亦同"""print(np.sum(a))print(np.sum(a,axis=0))print(np.sum(a,axis=1))print(np.sum(a,axis=2))print(np.prod(a))print(np.prod(a,axis=0))print(np.prod(a,axis=1))print(np.prod(a,axis=2))"""但需注意numpy可能存在溢位的问题"""nums=[14646444444,45656464662,55644445553,4555555555]print(np.prod(nums)) #溢位
参考资料Python精讲Numpy基础,大牛笔记详细解释
使用 Python 来认识矩阵 透过numpy
从零开始学资料科学:Numpy 基础入门
NumPy for Matlab users
No related posts.