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

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

附: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遇到的问题就这些,以后还会补充,欢迎评论学习交流!