Python中矩阵的使用

在机器学习中,经常会用到矩阵,在python语言中,向量、矩阵等抽象概念如何表示和使用,自己之前一直有些搞不明白,今天就试着总结下吧。


问题

自己需要明确的一些问题:

  • python中list,二维list如何操作
  • numpy中array,二维array如何操作
  • python list和numpy array的区别,转化
  • 向量如何表示
  • 矩阵的一些常用操作
  • 向量、矩阵的运算

list

python内置了list,也就是数组,可以用来表示向量和矩阵:

1
2
3
4
5
6
7
l = [1, 2, 3] # 1-d list
l[:] # [1, 2, 3]
l[:2] # [1, 2]
l[1:] # [2, 3]
l[1] # [2]
l[-1] # [3]
l[-2] # [2]

关于下标,文档里一张图说的很清楚:

1
2
3
4
5
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1

2d-list:

表示矩阵可以用python的2维list:

1
2
3
4
5
6
7
mat = [
[1, 2, 3],
[4, 5, 6]
]
# mat
# [[1, 2, 3], [4, 5, 6]]

表示上呢,python内置的list也就这么回事,具体使用的时候,有一些操作还是值得注意的。
关于list所有可以的操作,文档中给出了:https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range
(真难找,python的文档咋这么不清楚,把reference和tutorial放在一起的感觉,不喜欢)

+*的操作,就是concat:

1
2
3
l = [1, 2, 3]
l + l # [1, 2, 3, 1, 2, 3]
l * 3 # [1, 2, 3, 1, 2, 3, 1, 2, 3]

NumPy Array

在机器学习中,好多代码第一行就是import numpy as np哈哈,的确,用numpy的array会更多一些,操作也更丰富一些

ndarray对多维支持很友好,从名字就可以看出来

基本属性

常用的有:

  • ndim
  • shape
  • size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [7]: a = np.array(
...: [[1, 2, 3],
...: [4, 5, 6]]
...: )
In [8]: a
Out[8]:
array([[1, 2, 3],
[4, 5, 6]])
In [9]: a.shape
Out[9]: (2, 3)
In [10]: type(a.shape)
Out[10]: tuple
In [11]: a.dtype
Out[11]: dtype('int64')
In [12]: a.ndim
Out[12]: 2
In [13]: a.size
Out[13]: 6

创建

直接从list创建:

1
2
3
4
5
6
7
8
9
10
11
12
In [16]: np.array([1, 2, 3])
Out[16]: array([1, 2, 3])
In [17]: np.array([[1, 2, 3], [4, 5, 6]])
Out[17]:
array([[1, 2, 3],
[4, 5, 6]])
In [18]: np.array([(1, 2, 3),(4, 5, 6)])
Out[18]:
array([[1, 2, 3],
[4, 5, 6]])

用方便的一些填充函数:

1
2
3
4
5
6
7
In [22]: np.zeros((2, 3))
Out[22]:
array([[0., 0., 0.],
[0., 0., 0.]])
In [23]: np.zeros(3)
Out[23]: array([0., 0., 0.])

类似的还有np.ones()np.empty()

np.arange()或者np.linspace()生成一定间隔的数据,其实用的比较少

运算

numpy文档:

Arithmetic operators on arrays apply elementwise. A new array is created and filled with the result.

所以,一些基本的操作就明确了,比如:*, **
特别要注意是*,并不是矩阵乘法,而是elementwise的乘法

sum, min, max:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In [9]: a = np.array([[1,2,3],[4,5,6]])
In [10]: a.sum()
Out[10]: 21
In [11]: a.sum(axis=0)
Out[11]: array([5, 7, 9])
In [12]: a.sum(axis=1)
Out[12]: array([ 6, 15])
In [13]: a.min(axis=0)
Out[13]: array([1, 2, 3])
In [14]: a.min()
Out[14]: 1
In [15]: a.max()
Out[15]: 6

当然也可以用python自己的函数min, max, sum,这其中应该会有一个cast的过程

shape操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
In [16]: a
Out[16]:
array([[1, 2, 3],
[4, 5, 6]])
In [17]: a.reshape(3, 2)
Out[17]:
array([[1, 2],
[3, 4],
[5, 6]])
In [20]: a.reshape(3, -1) # -1表示自动计算
Out[20]:
array([[1, 2],
[3, 4],
[5, 6]])
In [21]: a.resize(3, 2)
In [22]: a
Out[22]:
array([[1, 2],
[3, 4],
[5, 6]])

stack & split

hstack vstack:分别水平堆叠和垂直堆叠

hsplit vsplit: 分别水平气氛和垂直切分

copy

  • no copy (alias): b = a
  • shallow copy: b = a.view()
  • deep copy: b = a.copy()

vector vs. matrix

之前自己一直有疑惑的是,numpy中的vector和matrix有什么关系,是不是一样的。
因为,在运算的过程中,经常需要矩阵和向量之间进行运算,有时候会有对不齐的操作。

经过了解,明确了,一维数组和矩阵中的行向量或者列向量是不一样的!不能直接进行运算!!

两者的相互转化及运算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
In [43]: a = np.array([1, 2, 3])
In [44]: rv = np.array([a]) # 转换成行向量,(3,) -> (1, 3)
In [45]: rv
Out[45]: array([[1, 2, 3]])
In [46]: cv = np.vstack(a) # 转换成列向量,(3,) -> (3, 1)
In [47]: cv
Out[47]:
array([[1],
[2],
[3]])
In [48]: cv @ rv
Out[48]:
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
In [52]: rv[0] # 行向量 -> array
Out[52]: array([1, 2, 3])
In [53]: cv[:, 0] # 列向量 -> array
Out[53]: array([1, 2, 3])

总结

用NumPy的array,会比自带的强大很多!

一维array和矩阵中的行向量和列向量不一样!

NumPy的文档还是很清晰的,有问题找文档!(Python的文档是真的辣鸡呀~)