0
点赞
收藏
分享

微信扫一扫

matlab和python操作矩阵的异同点

勇敢的趙迦禾 2022-04-04 阅读 70
python

随着Pytorch、TensorFlow等机器学习框架的兴起,很多实例都是基于Python实现的。而我自己专业内的程序都是基于MATLAB实现的,所以要结合网上的机器学习代码就有些不方便了,因此就萌生了将MATLAB代码转为Python代码的想法。

最近将MATLAB程序转为Python程序时,遇到了一些坑,在这里列举说明一下,以免再次入坑。这里主要涉及的是对矩阵的操作。Python中用到的主要是numpy库,这里只考虑使用np.array生成数组,不考虑matrix。

  1. 使用linsapce生成矩阵

MATLAB:

linspace(1,12,12)

结果:

1     2     3     4     5     6     7     8     9    10    11    12

numpy:

import numpy as np
print(np.linspace(1, 12, 12))

结果:

[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12.]

2. 生成等间距递增矩阵(生成1,2,3,4,5,6,7,8)

matlab: 

1:1:8

结果

1     2     3     4     5     6     7     8

numpy:

print(np.arange(1, 9, 1)) #注意这里是9,而不是8

结果

[1 2 3 4 5 6 7 8]

3. 生成一个3×3的全零矩阵或全1矩阵

matlab

ones(3,3) %全1矩阵

结果

   1     1     1
   1     1     1
   1     1     1

numpy

print(np.ones((3,3)))

结果

[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]

坑:

print(np.ones(3,3))

报错

TypeError: data type not understood

注意一定要加括号

4. 拼接矩阵

在MATLAB中拼接矩阵是很容易的。

[A B] %矩阵A和矩阵B左右拼接
[A;B] %矩阵A和矩阵B上下拼接

在numpy中可以使用np.concatenate((A,B),axis=1) 水平拼接两个矩阵,axis=0时垂直拼接矩阵。 也可以使用np.vstack((A,B)) 垂直拼接两个矩阵。

import numpy as np
A = np.ones((2,2))
B = np.zeros((2,2))
C = np.concatenate((A, B), axis=1)
D = np.concatenate((A, B), axis=0)
E = np.vstack((A,B))
print(C)
print(D)
print(E)

结果

[[1. 1. 0. 0.]
 [1. 1. 0. 0.]]

[[1. 1.]
 [1. 1.]
 [0. 0.]
 [0. 0.]]

[[1. 1.]
 [1. 1.]
 [0. 0.]
 [0. 0.]]

5. 矩阵的乘法

在MATLAB中:A*B 表示两矩阵相乘,两个矩阵的维度必须满足相乘的条件 

A.*B 表示矩阵对应元素相乘

a=[1 2;3 4]
b=[4 5;6 7]
a*b
a.*b

结果

a =

     1     2
     3     4

b =

     4     5
     6     7

a*b
  
    16    19
    36    43

a.*b

     4    10
    18    28

在numpy中: A * B 表示矩阵对应元素相乘

np.dot(A, B) 表示矩阵相乘

import numpy as np
A = np.array(([1,2],[3,4]))
B = np.array(([4,5],[6,7]))
C = A * B
D = np.dot(A, B)
print(A)
print(B)
print(C)
print(D)

结果

[[1 2]
 [3 4]]

[[4 5]
 [6 7]]

[[ 4 10]
 [18 28]]

[[16 19]
 [36 43]]

6. 矩阵的转置

在MATLAB中 A.’ 表示A的转置,A’表示共轭转置,如果元素中有复数,虚部会变号。

>> A=[1+1j 2+2j;3+3j 4+4j]

A =

   1.0000 + 1.0000i   2.0000 + 2.0000i
   3.0000 + 3.0000i   4.0000 + 4.0000i

>> A.'

ans =

   1.0000 + 1.0000i   3.0000 + 3.0000i
   2.0000 + 2.0000i   4.0000 + 4.0000i

>> A'

ans =

   1.0000 - 1.0000i   3.0000 - 3.0000i
   2.0000 - 2.0000i   4.0000 - 4.0000i

在numpy中,np.transpose(A) 相当于MATLAB中的A.’

import numpy as np
A = np.array(([1+1j,2+2j],[3+3j,4+4j]))
print(A)
print(np.transpose(A))

结果

[[1.+1.j 2.+2.j]
 [3.+3.j 4.+4.j]]

[[1.+1.j 3.+3.j]
 [2.+2.j 4.+4.j]]

在numpy中,共轭矩阵可以使用A.conjugate() 计算

import numpy as np
A = np.array(([1+1j,2+2j],[3+3j,4+4j]))
print(A)
print(A.conjugate())

结果

[[1.+1.j 2.+2.j]
 [3.+3.j 4.+4.j]]

[[1.-1.j 2.-2.j]
 [3.-3.j 4.-4.j]]

7. 复数类型的声明

在numpy中,如果不声明变量是复数类型的,很可能会导致计算结果出现nan。

import numpy as np
a = -1
print(np.sqrt(a))

结果

RuntimeWarning: invalid value encountered in sqrt
  print(np.sqrt(a))
nan

解决办法:定义变量时声明为复数类型

import numpy as np
a = np.array(-1, dtype = complex)
print(np.sqrt(a))

结果

1j

坑:如果一次计算中涉及多个复数变量,最好将这些变量都设置为复数类型,以免出错。

生成全1或全0矩阵也要声明为复数类型。

np.zeros((1, N),dtype = complex)

否则可能会出现以下警告:

RuntimeWarning: invalid value encountered in...
或
ComplexWarning: Casting complex values to real discards the imaginary part

8. 求矩阵的特征值

MATLAB:[V, D] = eig(A) 其中矩阵A的全部特征值构成对角矩阵D,而A的特征向量构成列向量V。

>> a=[1 2;3 4]

a =

     1     2
     3     4

>> [V, D]=eig(a)

V =

   -0.8246   -0.4160
    0.5658   -0.9094


D =

   -0.3723         0
         0    5.3723

Numpy:VV, DD = np.linalg.eig(A) 其中VV是特征值,DD是特征向量。

import numpy as np
a = np.array(([1,2],[3,4]))
VV, DD = np.linalg.eig(a)
print(VV)
print(DD)

结果

[-0.37228132  5.37228132]

[[-0.82456484 -0.41597356]
 [ 0.56576746 -0.90937671]]

坑:有两点不同:1.MATLAB和numpy返回特征值和特征向量的顺序是反的;2.MATLAB返回的特征值是对角矩阵形式,而numpy返回的特征值是一个数组。

9. 求逆矩阵

MATLAB: inv(A)

A=[1 2;3 4]

A =

     1     2
     3     4

>> inv(A)

ans =

   -2.0000    1.0000
    1.5000   -0.5000

numpy : np.linalg.inv(A)

import numpy as np
a = np.array(([1,2],[3,4]))
print(np.linalg.inv(a))

结果

[[-2.   1. ]
 [ 1.5 -0.5]]

10. 矩阵的除法

计算矩阵的除法MATLAB有两种方式。

MATLAB 1: A\B 表示矩阵B除矩阵A

MATLAB 2:inv(A) * B 矩阵B除矩阵A,可以表示为A的逆矩阵乘矩阵B

A =

     1     2
     3     4

>> B=[2 3;4 5]

B =

     2     3
     4     5

>> A\B

ans =

     0    -1
     1     2

>> inv(A)*B

ans =

         0   -1.0000
    1.0000    2.0000

Numpy:np.dot(np.linalg.inv(A), B) 

import numpy as np
A = np.array(([1,2],[3,4]))
B = np.array(([2,3],[4,5]))
print(np.dot(np.linalg.inv(A), B))

结果

[[ 4.4408921e-16 -1.0000000e+00]
 [ 1.0000000e+00  2.0000000e+00]]

11. 矩阵连乘

MATLAB: A*B*C 表示三个矩阵A、B、C连乘

A =

     1     2
     3     4

>> B

B =

     2     3
     4     5

>> C=[3 4;5 6]

C =

     3     4
     5     6

>> A*B*C

ans =

    95   118
   211   262

numpy:np.dot(A,B,C)是错误的,实际上只计算了矩阵A乘矩阵B

import numpy as np
A = np.array(([1,2],[3,4]))
B = np.array(([2,3],[4,5]))
C = np.array(([3,4],[5,6]))
print(np.dot(A,B))
print(np.dot(A,B,C))

结果

[[10 13]
 [22 29]]

[[10 13]
 [22 29]]

对于numpy中三个矩阵的连乘,可以先计算前两个矩阵的乘积,再与第三个矩阵相乘。

import numpy as np
A = np.array(([1,2],[3,4]))
B = np.array(([2,3],[4,5]))
C = np.array(([3,4],[5,6]))
print(np.dot(np.dot(A,B), C))

结果

[[ 95 118]
 [211 262]]

很显然,这种方法有缺陷,对于更多数量的矩阵连乘时比较麻烦。

12. 对角矩阵

MATLAB: diag(A) 将一维数组A变成对角矩阵

>> A=1:1:4

A =

     1     2     3     4

>> diag(A)

ans =

     1     0     0     0
     0     2     0     0
     0     0     3     0
     0     0     0     4

numpy: np.diag() 。 需要注意数组的维度

import numpy as np
a = np.arange(1,5,1)
b = np.ones((1,3))
print(np.diag(a))
print(np.diag(b)) #这时并没有生成对角矩阵
print(np.diag(b[0, :]))

结果

[[1 0 0 0]
 [0 2 0 0]
 [0 0 3 0]
 [0 0 0 4]]

[1.]

[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

13. 矩阵赋值

这里用Python很容易出错,一定要特别注意。

在MATLAB中使用‘=’赋值,变量之间并没有联系。

>> a=ones(2,2)

a =

     1     1
     1     1

>> b=a

b =

     1     1
     1     1

>> a(1,2)=0;
>> a

a =

     1     0
     1     1

>> b

b =

     1     1
     1     1

而在Python中,使用“=”并非仅仅是将变量a的值赋值给变量b。一旦使用“a=b”,就表示今后,a就是b,b就是a。改变a,b也跟着改变;改变b,a也跟着改变。

import numpy as np
a = np.ones((2,2))
b = a
a[0, 1] = 0
print(a)
print(b)

结果:改变变量a, b也跟着改变了。

[[1. 0.]
 [1. 1.]]

[[1. 0.]
 [1. 1.]]

同样,改变变量b,a也会跟着改变

import numpy as np
a = np.ones((2,2))
b = a
b[0, 1] = 0
print(a)
print(b)

结果

[[1. 0.]
 [1. 1.]]

[[1. 0.]
 [1. 1.]]

解决:1.使用.copy() 或避免直接赋值

import numpy as np
a = np.ones((2,2))
b = a
c = a.copy()
a[0, 1] = 0
print(a)
print(b)
print(c)

结果

[[1. 0.]
 [1. 1.]]

[[1. 0.]
 [1. 1.]]

[[1. 1.]
 [1. 1.]]

2.通过*1避免直接赋值

未×1

import numpy as np
a = np.arange(0,20,1)
b = a[15:20]
b[ 3:] = 0  #改变b时,a也跟着改变了
c = a[10:]
print(a)
print(b)
print(c)

结果

[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17  0  0] 
[15 16 17  0  0]  
[10 11 12 13 14 15 16 17  0  0]  

通过×1避免

import numpy as np
a = np.arange(0,20,1)
b = a[15:20] * 1
b[ 3:] = 0
c = a[10:]
print(a)
print(b)
print(c)

结果

[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]
[15 16 17  0  0]
[10 11 12 13 14 15 16 17 18 19]

14. 矩阵的减法

没错,你没看错,减法也有坑。这主要源于MATLAB中是不存在一列多行矩阵的,而Python中则不一样。请看下面。

import numpy as np
a = np.array([1,2,3,4,5,6])
b = np.ones((6,1))
c = b - a

猜猜看,结果是多少?我本以为会是[0,-1,-2,-3,-4,-5]。然而结果却如下所示:

[[ 0. -1. -2. -3. -4. -5.]
 [ 0. -1. -2. -3. -4. -5.]
 [ 0. -1. -2. -3. -4. -5.]
 [ 0. -1. -2. -3. -4. -5.]
 [ 0. -1. -2. -3. -4. -5.]
 [ 0. -1. -2. -3. -4. -5.]]

6行1列的矩阵减去1行6列的矩阵,变成了6行6列的矩阵,怎么减法的维度也满足矩阵乘法维度口诀了?

莫慌,将b转置后再相减即可

import numpy as np
a = np.array([1,2,3,4,5,6])
b = np.ones((6,1))
b = b.reshape(1,-1)
c = b - a
print(c)

结果:

[[ 0. -1. -2. -3. -4. -5.]]

15. 含有等间距数列的生成

在MATLAB里,要生成一个这样的数组是很简单的,如下所示:

>> a=[1 2:2:12 13]

a =

     1     2     4     6     8    10    12    13

但python中使用numpy生成矩阵时无法使用“:”运算符。可以使用如下方法:

import numpy as np
array1 = np.array([1, 2, 4, 6, 8, 10, 12, 13])
array2 = np.array([1, np.linspace(2,12,6), 13])
array3 = np.array([1, list(range(2,14,2)), 13])

print(array1)
print(array1.shape)

print(array2)
print(array2.shape)

print(array3)
print(array3.shape)
array4 = array2 + array3
print(array4)

结果:

[ 1  2  4  6  8 10 12 13]
(8,)
[1 array([ 2.,  4.,  6.,  8., 10., 12.]) 13]
(3,)
[1 list([2, 4, 6, 8, 10, 12]) 13]
(3,)
[2 array([ 4.,  8., 12., 16., 20., 24.]) 26]

附:numpy中需要特别注意的事情

1 数组的维度

MATLAB中没有一维数组,即使是一行数字也会认为行的大小是1,但numpy中却不一样,看下面这个例子

import numpy as np
a = np.array([[1,2,3],[4,5,6]])
b = a[:,0:1]  #注意b和c的区别
c = a[:,0]
print(a)
print(a.shape)
print(b)
print(b.shape)
print(c)
print(c.shape)

结果

[[1 2 3]
 [4 5 6]]
(2, 3)
[[1]
 [4]]
(2, 1)
[1 4]
(2,)

可以看到b和c的维度是不一样的,b是二维的,而c是一维的。因为没有注意到这点,所以我在使用TensorFlow2.1建立网络时遇到了下面的错误。很显然,就是b和c的区别。

ValueError: Input 0 of layer dense is incompatible with the layer: : expected min_ndim=2, found ndim=1. Full shape received: [None]

总结:目前从MATLAB转到numpy遇到的问题就这些,以后还会补充,欢迎评论学习交流!

 

举报

相关推荐

0 条评论