Python_tips-翻转拼接矩阵

万壑松风知客来,摇扇抚琴待留声

1. 文起

NumPy 是 Python 语言的一个扩展程序库。支持高端大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库,是 Python 作为数据分析语言最有力的一个工具包之一。

个人很喜欢使用 Numpy,它除了运算速度极快,数据处理能力和技巧也是相当了得。本文将以矩阵处理中其中两个例子来叙述——翻转矩阵和拼接矩阵。

在数据处理中,很多数据其实都是以矩阵的方式表达的,因为矩阵运算速度更快更方便。例如上一篇《距离矩阵》中通过构建矩阵可以极大程度上优化运算。再例如在图像中,每一张图片其实都是由像素矩阵构成的。通过矩阵广播的功能可以远大于循环的处理方式。

2. 翻转矩阵

在 Python 中进行矩阵运算时有很多方法都可以对矩阵进行翻转处理,下面以 Numpy 为例,通过调用其相关函数实现矩阵的翻转。

numpy.flip(m,axis=None) 是一个强大的翻转矩阵函数,虽然只有两个超参数。其中 m 是传入原始矩阵,axis 是翻转的维度轴,这个参数很重要,下面具体说说:

矩阵是一个有维度的数据,例如最简单的一维矩阵也有 x 轴方向,然后二维矩阵有 x、y 轴方向,再然后三维矩阵有 x、y、z 轴方向,以此类推。翻转的原理就是沿着某个轴对该矩阵进行对称翻转

所以 axis 的作用就是给定翻转轴。当不指定参数 axis=None 时,表示会依次对矩阵的每个维度进行翻转;axis=0 表示沿着第一个维度轴翻转;axis=1 表示沿着第二个维度轴翻转;axis=2、3、4…… 依次类推;同时还可以传入元组,指定某些轴翻转,如:axis=(0, 2) 表示依次沿着第一、第三个轴翻转;最后如果参数为负数 axis=-1、-2、-5 表示沿着倒数这个维度轴进行翻转。

强调:所指定的 axis 参数维度轴,在原始矩阵中一定要相应的轴,不能二维数据要求它三维翻转。

为了更容易理解,下面我们用代码分别处理一、二、三维矩阵。

一维:

1
2
3
4
5
6
matrix_1 = np.arange(5)
# [0 1 2 3 4]

# 等同于axis=None,等同于axis=-1
matrix_1_flip_0 = np.flip(matrix_1, axis=0)
# [4 3 2 1 0]

二维:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
matrix_2 = np.arange(9).reshape((3,3))
# [[0 1 2]
# [3 4 5]
# [6 7 8]]

# 沿y轴翻转
matrix_2_flip_0 = np.flip(matrix_2, axis=0)
# [[6 7 8]
# [3 4 5]
# [0 1 2]]

# 沿x轴翻转
matrix_2_flip_1 = np.flip(matrix_2, axis=1)
# [[2 1 0]
# [5 4 3]
# [8 7 6]]

# x、y轴都翻转。等同于axis=(0,1)
matrix_2_flip_all = np.flip(matrix_2)
# [[8 7 6]
# [5 4 3]
# [2 1 0]]

三维:

为了更直观的观察翻转矩阵,在三维中我们通过翻转像素矩阵也就是图片,来观察翻转的结果。

1
2
3
4
5
6
import cv2
# 原始图片
matrix_3 = cv2.imread(r'./images.jpg')
matrix_3 = cv2.resize(matrix_3,(400,400))
cv2.imshow('show', matrix_3)
cv2.waitKey()

1
2
3
4
5
# 沿y轴上下翻转
matrix_3_flip_0 = np.flip(matrix_3, axis=0)
# cv2.imwrite(r'./1.jpg', matrix_3_flip_0)
cv2.imshow('show', matrix_3_flip_0)
cv2.waitKey()

1
2
3
4
# 沿x轴左右翻转
matrix_3_flip_1 = np.flip(matrix_3, axis=1)
cv2.imshow('show', matrix_3_flip_1)
cv2.waitKey()

1
2
3
4
5
# 沿z轴翻转(对于图像来说z轴就是通道,如这里的BGR翻转为了RGB)
matrix_3_flip_2 = np.flip(matrix_3, axis=2)
cv2.imshow('show', matrix_3_flip_2)
cv2.waitKey()
cv2.destroyAllWindows()

flip 有两个简化的翻转方法,左右翻转的 fliplr(m),上下翻转的 flipup(m),通过 flip 指定 axis 参数也可以完成,所以这里就不累述了。

3. 拼接矩阵

另一种常用的矩阵处理方法——拼接矩阵。很多时候我们需要对不同数据矩阵进行处理,最后再合并这些结果矩阵。

同样这里将使用 Numpy 实现该功能。 numpy.stack(arrays,axis=0,out=None) 是一个强大的拼接矩阵函数。包括参数 arrays 表示传入的原始数据,axis 表示指定的拼接维度方向,out 表示结果输出位置(一般不用指定,深度学习中可能用的多)。

拼接时也会遇到不同维度矩阵的问题,下面用具体数据来看看。

一维数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
matrix_a = np.arange(5)
matrix_b = np.arange(5)
# [0 1 2 3 4]

# 行拼接:
matrix_c = np.stack((matrix_a, matrix_b), axis=0)
# [[0 1 2 3 4]
# [0 1 2 3 4]]

# 列拼接:
matrix_d = np.stack((matrix_a, matrix_b), axis=1)
# [[0 0]
# [1 1]
# [2 2]
# [3 3]
# [4 4]]

二维数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
matrix_a = np.arange(4).reshape((2,2))
# [[0 1]
# [2 3]]

matrix_b = (np.ones((2,2))*4).reshape((2,2))
# [[4. 4.]
# [4. 4.]]

matrix_c = np.stack((matrix_a, matrix_b), axis=0)
# [[[0. 1.]
# [2. 3.]]
# [[4. 4.]
# [4. 4.]]]
print(matrix_c.shape)
# (2, 2, 2)

matrix_d = np.stack((matrix_a, matrix_b), axis=1)
# [[[0. 1.]
# [4. 4.]]
# [[2. 3.]
# [4. 4.]]]
print(matrix_d.shape)
# (2, 2, 2)

矩阵的拼接相对于矩阵的翻转理解起来要有一定的难度,这里暂不做过多的文字描述,想了解的更清楚,可以使用具体数据进行实践。

当然 stack 函数也有两个简化后的处理方法 hstackvstack ,这两种方法分别对应上面一维处理的列拼接、行拼接。

4. 文末

翻转矩阵和拼接矩阵是两个很常见的处理方式。虽然这里记录的内容较少,但实际两者都需要花大量的时间去实践后才能融会贯通,面对高维数据处理时尤为重要。