赞
踩
线性代数是代数学的一个分支,主要处理线性关系问题 ( 简称线性问题) 。线性代数中的概念是机器学习必备的基础知识,有助于理解不同机器学习算法背后的原理、算法内部是如何运行的,以便在开发机器学习系统时更好地作决策。在机器学习的背景下,线性代数也是一个数学工具,提供了像向量和矩阵这样的数据结构用于组织大量的数据,同时也提供了如加、减、乘、求逆等有助于同时操作数据的运算,从而将复杂的问题简单化,提升大规模运算的效率。本篇文章将总结一些机器学习中涉及的线性代数中的基础知识,包括向量、矩阵、行列式 、线性方程等基本概念;常见的特殊矩阵,矩阵的加、减、 乘法运算,向量与矩阵的乘法、向量的内积运算、逆矩阵和转置矩阵等慨念,同时提供相应的 Python 实现代码。
向量是线性代数最基础、最根源的组成部分,也是机器学习的基础数据表示形式。机器学习中的投影 、 降维等概念,都是在向量的基础上实现的。线性代数通过将研究对象拓展到向量,对多维的数据进行统一研究,进而演化出一套计算的方法,使我们可以非常方便地研究和解决真实世界中的问题。
标量也称为“无向量”,是用一个单独的数表示其数值的大小(可以有正负之分),可以是实数或复数, 一般用小写的变量名称表示。 例如,用 s s s 表示行走的距离,用 k k k 表示直线的斜率,用 n n n 表示数组中元素的数目, s s s、 k k k、 n n n 都可以看作标量。
真实世界是多维度的,而且大多数的研究对象也具有非常多的维度,因此用一个数很难表达和处理真实世界中的问题,这就需要用一组数,也就是用向量来表达和处理高维空间中的问题。为表示一个整体,习惯上将这组数用方括号括起来。
定义1 将 n n n 个有次序的数排成一行,称为 n n n 维行向量;将 n n n 个有次序的数排成一列,称为 n n n 维列向量。
如
x
=
[
1
2
3
4
]
,
y
=
[
1
2
3
4
]
\mathbf{x} =
从几何意义上看,向量既有大小又有方向,将向量的分量看作坐标轴上的坐标,该向量可以被看作空间中的一个点。以坐标原点为起点,以向量代表的点为终点,可以形成一条有向线段。 有向线段的长度表示向量的大小,箭头所指的方向表示向量的方向,可以将任意一个位置作为起始点进行自由移动,但一般将原点看作起始点。 如图 1 所示,点 ( 3 , 4 ) (3,4) (3,4) 和点 ( 4 , 3 ) (4,3) (4,3) 分别对应向量 [ 3 , 4 ] T \left [ 3,4 \right ]^{T} [3,4]T 和向量 [ 4 , 3 ] T \left [ 4,3 \right ]^{T} [4,3]T,显然向量是有序的, [ 3 , 4 ] T \left [ 3,4 \right ]^{T} [3,4]T 和 [ 4 , 3 ] T \left [ 4,3 \right ]^{T} [4,3]T 分别代表不同的向量。
在一些机器学习的算法中,经常会用到向量的加法运算。
求两个向量和的运算叫作向量的加法。向量加法的值等于两个向量的对应分量之和。
以两个二维向量的加法为例,如: r = [ 3 , 1 ] T \mathbf{r} = \left [ 3,1 \right ]^{T} r=[3,1]T 和 s = [ 2 , 3 ] T \mathbf{s} = \left [ 2,3 \right ]^{T} s=[2,3]T,则 r + s = [ 3 + 2 , 1 + 3 ] T = [ 5 , 4 ] T \mathbf{r}+\mathbf{s} = \left [ 3+2,1+3 \right ]^{T}=\left [ 5,4 \right ]^{T} r+s=[3+2,1+3]T=[5,4]T。
在二维平面内,可以将向量加法理解为求以这两个向量为边的平行四边形的对角线表示的向量。如图2所示,即从原点出发,先沿 x x x 轴方向移动3个单位,再沿 y y y 轴方向移动1个单位,得到 r \mathbf{r} r 的位置, r \mathbf{r} r 加上 s \mathbf{s} s,可以理解为继续沿着 x x x 轴方向移动2个位置,再沿 y y y 轴方向移动3个位置,最终到达的位置 ( 5 , 4 ) (5,4) (5,4) 就是 r + s \mathbf{r} + \mathbf{s} r+s 对应的向量 [ 5 , 4 ] T \left [ 5,4 \right ]^{T} [5,4]T。
数乘向量是数量与向量的乘法运算。一个数 m m m 乘一个向量 r \mathbf{r} r,结果是向量 m r m\mathbf{r} mr。以一个二维向量的数乘为例,如 m = 3 m=3 m=3, r = [ 2 , 1 ] T \mathbf{r} = \left [ 2,1 \right ]^{T} r=[2,1]T,则 m r = [ 3 × 2 , 3 × 1 ] T = [ 6 , 3 ] T m\mathbf{r} =\left [ 3\times2,3\times1 \right ]^{T}=\left [ 6,3 \right ]^{T} mr=[3×2,3×1]T=[6,3]T。
在二维平面内,
3
r
3\mathbf{r}
3r 即3个
r
\mathbf{r}
r 相加,可以理解为从
r
\mathbf{r}
r 位置出发,沿着
x
x
x 轴方向再移动
2
×
2
2\times2
2×2 个单位,沿着
y
y
y 轴方向再移动
2
×
1
2\times1
2×1个单位,到达的位置
(
6
,
3
)
(6,3)
(6,3) 即
3
r
3\mathbf{r}
3r 对应的向量
[
6
,
3
]
T
\left [ 6,3 \right ]^{T}
[6,3]T,如图3所示。
在机器学习中,对一个对象或事件的描述称为样本,反映样本某方面的表现或性质的事项称为特征或属性,特征的取值称为特征值,由样本组成的集合称为数据集。在数据集中,样本用向量表示,向量的维度可以看作样本的特征数。如经典的鸢尾花数据集,用萼片长度、萼片宽度、花瓣长度和花瓣宽度 4 4 4 个特征刻画鸢尾花,4个特征值组成一个样本,用四维行向量表示。如一个行向量 [ 5.1 , 3.5 , 1.4 , 0.2 ] [5.1,3.5,1.4,0.2] [5.1,3.5,1.4,0.2] 表示一个鸢尾花样本,则有 5.1 5.1 5.1、 3.5 3.5 3.5、 1.4 1.4 1.4 和 0.2 0.2 0.2 共 4 4 4 个特征值。
标量是一个数,向量是对标量的扩展,是一组数;矩阵是对向量的扩展,可看作一组向量。在图像处理、人工智能等领域,常用矩阵来表示和处理大量的数据。矩阵是线性代数中最有用的工具。
定义2 由 m × n m \times n m×n 个数 a i j a_{ij} aij, i = 1 , 2 , . . . , m ; j = 1 , 2 , . . . , n i=1,2,...,m;\: j = 1,2,...,n i=1,2,...,m;j=1,2,...,n 排成的 m m m 行 n n n 列的数表,称为 m m m 行 n n n 列矩阵,简称 m × n m \times n m×n 阶矩阵,记作,
简记为 A = A m × n = ( a i j ) m × n A = A_{m \times n} = \left ( a_{ij} \right )_{m \times n} A=Am×n=(aij)m×n。其中 a i j a_{ij} aij 称为矩阵的元素, a i j a_{ij} aij 的第1个下标 i i i 称为行标,表明该元素位于第 i i i 行;第 2 个下标 j j j 称为列标,表明该元素位于第 j j j 列。
将元素为实数的矩阵称为实矩阵,元素为复数的矩阵称为复矩阵。在实际使用的过程中,一般都是实矩阵。
从数组的角度看,向量是一维数组,是标量的数组;矩阵是二维数组,是向量的数组。
给定一个矩阵,可以将其看作由行向量构成,也可以看作是由列向量组成 。
例如:矩阵
A
A
A
按行看,可以看作由 [120, 3, 2, 2, 0.2, 600] 、 [100, 3, 1, 2, 0.2, 500] 、 [110, 3, 1, 2, 0.1, 700] 和 [90, 3, 1, 1, 1, 300] 四个六维行向量组成;按列看,则可以看作由
六个四维列向量构成。
向量可以看作一种特殊的矩阵, n × 1 n \times 1 n×1 阶矩阵可以称作一个 n n n 维列向量; 1 × n 1 \times n 1×n 阶矩阵也称为一个 n n n 维行向量。
矩阵的外观就是长方形的数表,生活中一些长方形的数表也可以看作矩阵,矩阵在日常生活、科学计算及机器学习中应用广泛,下面列举几个常见的例子。
【例1】生活中对象之间的关系常用表格表示。例如有 A , B 、 C 、 D 共 4 个城市,它们之间的通行关系如图 4 所示,习惯上用表 1 表示该图,行和列分别代表四个城市,用对号表示两个城市可以通行。计算机中可以用矩阵表示,行和列分别代表四个城市,使用 0 和 1 分别代表两个城市不可通行和可通行关系,表 1 对应的矩阵为 A A A。
通过矩阵运算,可以判断两个城市间是否可达。
【例2】编号为 1~4 的 4 个学生选修了 A 、 B 、 C 、 D 、 E 共 5 门课,每个学生每门课的成绩对应表 2 ,每行代表某学生 5 门课的成绩,每列代表某科目 4 个学生的成绩,该表格可以用矩阵 A A A 表示。
通过矩阵运算,可以求出每个学生或者每门课的平均分、最高分和最低分,以及每门课的分数分布情况等。
【例3】在机器学习中,样本集合(也称为数据集)常用矩阵表示,每行数据称为一个样本(或一个数据对象),每列表达样本的一个特征 ( 属性 ) 或者标记,例如表 3 的鸢尾花数据集,每一行代表一个样本。前四列分别代表一个特征,最后一列是标记,表示所属类别。 该数据集可以用矩阵 A A A 表示
在机器学习中,常用矩阵 X X X 表示矩阵 A A A 的前四列,矩阵 Y Y Y 表示矩阵 A A A 的最后一列,获取 X X X 和 Y Y Y 后,将它们带入机器学习的相关算法中实现分类。
【例4】用矩阵表示线性系统。
描述参数、变量和常量之间线性关系的线性系统常用线性方程组表示,未知量均为一次项的方程组称为线性方程组。
例如,设某个线性系统用如下的线性方程组表示。
将该方程组左侧的系数用一个 m × n m \times n m×n 阶矩阵 A A A 表示,每行代表一个方程,每列代表在不同方程中不同未知数的系数。方程组右侧的值用 m × 1 m \times 1 m×1 阶矩阵 B B B 表示,每行代表方程右侧的值,未知数 X X X 用 n × 1 n \times 1 n×1 阶矩阵表示。习惯上称 A A A 为系数矩阵, X X X 为未知数矩阵, B B B 为常数项矩阵。 此线性方程组记为 A X = B AX=B AX=B,其中:
记
为增广矩阵。
利用矩阵运算,借助 Python
的 NumPy
库很容易求出
X
X
X 值。
【例5】在平面坐标系中,一个点的坐标用二维向量存放,如图 5 所示,若干点的坐标可以用矩 A A A 存放。
代表平面坐标中的 5 个点。
【例6】数字图像的数据可以用矩阵表示,如灰度图像的像素数据就是一个矩阵,矩阵的行对应图像的高(单位为像素),矩阵的列对应图像的宽(单位为像素),矩阵的元素对应图像的像素,矩阵元素的值就是像素的灰度值。如图 6 所示,数字图像部分的灰度值对应的矩阵为 A A A。
采用矩阵存储数字图像,符合二维图像的行列特性,也便于通过矩阵理论和矩阵算法对数字图像进行分析和处理。
NumPy 库是 Python 的一种开源的数值计算扩展,提供很多高效的数值编程工具。它的数组计算,是矩阵操作必不可少的包。NumPy 库可用于存储和处理大型矩阵,比 Python 自身的嵌套列表结构要高效得多(该结构也可以表示矩阵)。
在 Python 中使用 NumPy 库,首先需要安装 NumPy 库,导人 NumPy 库之后,就可以使用 NumPy 库中的方法。
对于 NumPy 库的安装由于不同的系统安装方式会有不同,大家可以根据自己的系统自行搜索相关资料进行安装。
导入 NumPy 库的方式有以下 3 种,其中第 3 种方式最为常用 。
from numpy import * # 导入 numpy 的所有函数。
import numpy # 这个方式使用 numpy 的函数时,需要以 numpy. 开头。
import numpy as np # 这个方式使用 numpy 的函数时,需要以 np. 开头。
用第 3 种方法导入 NumPy 后,就可以使用 NumPy 库中的函数,如 shape 、 array 、 mat 等,调用方式都是 np.array()、 np.mat()、 np.shape(),不能写为 A.array()、 A.mat()、 A.shape() 等,其中 A 为变量。
NumPy 中常采用 matrix
(矩阵)和 array
(数组)表示矩阵,主要区别如下。
(1)matrix 是 array 的分支, matrix 和 array 基本上通用,但在大部分 Python 程序里, array 更为常用,因为 array 更灵活,速度更快。 官方文档建议使用二维 array 代替矩阵进行矩阵运算。array 的优势在于不仅可以表示二维数组,还能表示三,四,五, ⋯ \cdots ⋯, n n n 维数组。
(2)NumPy 中 array 的类型是 numpy.ndarray,由相同类型的元素组成。
根据给出的具体数据创建矩阵,将一切序列型的对象(包括其他数组) 作为 np.array() 函数的传入数据,进而产生 NumPy 数组。以二维列表或元组作为参数创建的二维数组即矩阵。如果传递的是多层嵌套序列,将创建多维数组。
下面的代码将实现矩阵的直接创建。
【代码】:
import numpy as np
A = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
arr1 = np.array(A) # 将列表转化为矩阵
print("A = ", A)
print("通过列表A创建的矩阵arr1\n", arr1)
B = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
arr2 = np.array(B) # 将元组转化为矩阵
print("B = ", B)
print("通过元组B创建的矩阵arr2\n", arr2)
【运行结果】:
A = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
通过列表A创建的矩阵arr1
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
B = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
通过元组B创建的矩阵arr2
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
【结果说明】:
通过 np.array() 函数将列表 A 或元组 B 生成 3x4 阶的矩阵 arr1 和 arr2 是相同的。
【提示】:
NumPy 中生成的矩阵有两层方括号。
(1)最外层的方括号表示矩阵
(2)内层有3对方括号,表示3行
(3)内存每对方括号内有4个元素,表示4列
(4)矩阵是按照行的顺序显示输出,这与 Python 的 list
类型不同
(5)方括号的形式可以判断数组是否能够代表一个向量或者矩阵
(6)list
类型用 “,”分隔,数组用空格分隔
矩阵的规模(大小) 一般用行数和列数描述,可以通过矩阵的 shape
属性获得,数据的类型可以使用 type()
函数验证。
【代码】:
print("A的类型:", type(A))
print("B的类型:", type(B))
print("arr1的类型:", type(arr1))
print("arr1的大小:", arr1.shape)
【运行结果】:
A的类型: <class 'list'>
B的类型: <class 'tuple'>
arr1的类型: <class 'numpy.ndarray'>
arr1的大小: (3, 4)
【结果说明】:
A、B 分别为列表和元组,它们与 arr1 的类型不同。 arr1 为 3x4 阶的矩阵。
【提示】:
可以使用 arr1.shape
或 np.shape(arr1)
获取 arr1 的规模,但是不可以使用 arr1.shape()
。
(1)随机生成矩阵元素
在机器学习中,常常会用随机数作为参数的数值,NumPy 中可以利用 np.random.random()
函数和np.random.randint()
函数分别随机生成矩阵中指定范围的浮点数和整数。
函数 np.random.random((d0, d1, ... ,dn))
生成值为 [0, 1) 区间的 n 维浮点数组,函数 np.random.random((d0, d1))
创建 d0xd1 阶矩阵。
函数 np.random.randint(low, high=None, size=None, dtype='I')
,返回随机整数,范围为 [Iow, high)。size 为数组维度,对于 d0xd1 阶矩阵,设 size=[d0, d1]。 dtype 为数据类型,默认的数据类型是 np.int,没有 high 时,默认生成随机数的范围是 [0, low)。
【代码】:
import numpy as np
arr1 = np.random.random((2, 3)) # 默认范围为0~1
print("创建的随机浮点数构成的2x3阶矩阵:\n", arr1)
arr2 = np.random.randint(3, 30, size=[2, 3])
print("创建的3~30(不包括30)之间的随机整数构成的2x3阶矩阵:\n", arr2)
【运行结果】:
创建的随机浮点数构成的2x3阶矩阵:
[[0.5674868 0.54082361 0.93320239]
[0.62330098 0.34546191 0.40427363]]
创建的3~30(不包括30)之间的随机整数构成的2x3阶矩阵:
[[19 22 24]
[11 17 17]]
(2)reshape() 函数通过改变矩阵的大小来创建新矩阵,其参数为一个正整数的元组,分别代表行数和列数
【代码】:
import numpy as np
A = [1, 2, 3, 4, 5, 6]
B = np.array(A) # 一维数组,共6个元素
C1 = B.reshape(2, 3) # 创建2行3列矩阵
C2 = B.reshape(3, 2) # 创建3行2列矩阵
print("矩阵B:\n", B)
print("转换为2行3列矩阵C1:\n", C1)
print("转换为3行2列矩阵C2:\n", C2)
【运行结果】:
矩阵B:
[1 2 3 4 5 6]
转换为2行3列矩阵C1:
[[1 2 3]
[4 5 6]]
转换为3行2列矩阵C2:
[[1 2]
[3 4]
[5 6]]
【提示】:
使用 reshape()
函数改变矩阵大小时,新矩阵的元素个数要与原矩阵的元素个数相等。当一个参数为 -1 时,reshape()
函数会根据另一个参数计算出 -1 代表的具体值,如上例中,C1 = B.reshape(2,3)
可用 C1 = B.reshape(2, -1)
或 C1 = B.reshape( -1, 3)
代替。
Python 中矩阵的下标是从 0 开始的,通过指定矩阵的下标,可实现存取对应的矩阵数据。对上例,获取 C1 和 C2 的部分元素。
【代码】:
import numpy as np
A = [1, 2, 3, 4, 5, 6]
B = np.array(A) # 一维数组,共6个元素
C1 = B.reshape(2, 3) # 创建2行3列矩阵
C2 = B.reshape(3, 2) # 创建3行2列矩阵
print("转换为2行3列矩阵C1:\n", C1)
print("转换为3行2列矩阵C2:\n", C2)
print("输出C1的第0行元素C1[0]:", C1[0]) # 获取矩阵的某一行
print("输出C1的前2行元素C1[0:2]:\n", C1[0:2]) # 获取矩阵的前几行
print("输出C2的第0行和第2行元素C2[[0,2]]:\n", C2[[0, 2]]) # 获取矩阵的某几行
print("输出C2的第1列元素C2[:,1]:\n", C2[:, 1]) # 获取矩阵的某一列
print("输出C2的前2列元素C2[:,0:2]:\n", C2[:, 0:2]) # 获取矩阵的前几列
print("输出C1的第0列和第2列元素C1[:,[0,2]]:\n", C1[:, [0, 2]]) # 获取矩阵的某几列
print("输出C2的第2行第1列元素C2[2,1]:", C2[2, 1]) # 获取矩阵的某个元素
【运行结果】:
转换为2行3列矩阵C1:
[[1 2 3]
[4 5 6]]
转换为3行2列矩阵C2:
[[1 2]
[3 4]
[5 6]]
输出C1的第0行元素C1[0]: [1 2 3]
输出C1的前2行元素C1[0:2]:
[[1 2 3]
[4 5 6]]
输出C2的第0行和第2行元素C2[[0,2]]:
[[1 2]
[5 6]]
输出C2的第1列元素C2[:,1]:
[2 4 6]
输出C2的前2列元素C2[:,0:2]:
[[1 2]
[3 4]
[5 6]]
输出C1的第0列和第2列元素C1[:,[0,2]]:
[[1 3]
[4 6]]
输出C2的第2行第1列元素C2[2,1]: 6
【结果说明】:可以用 -1 表示矩阵的最后一行或最后一列。获取到的矩阵的某一行或某一列的数据,类型为一维数组。
行向量可以看作是 1 × n 1 \times n 1×n 阶矩阵,而列向量可以看作是 n × 1 n \times 1 n×1 阶矩阵,因此可以采用创建矩阵的方式创建向量。
直接将数据以排列好的行列向量形式传递给array()
函数。
【代码】:
import numpy as np
A = [[1, 2, 3, 4, 5]]
B = [[1], [2], [3], [4], [5]]
C = np.array(A) # 创建行向量
D = np.array(B) # 创建列向量
print("行向量C:\n", C)
print("列向量D:\n", D)
print("A的类型:%s,C的类型:%s" % (type(A), type(C)))
print("B的类型:%s,D的类型:%s" % (type(B), type(D)))
print("C的大小:%s,D的大小:%s" % (C.shape, D.shape))
【运行结果】:
行向量C:
[[1 2 3 4 5]]
列向量D:
[[1]
[2]
[3]
[4]
[5]]
A的类型:<class 'list'>,C的类型:<class 'numpy.ndarray'>
B的类型:<class 'list'>,D的类型:<class 'numpy.ndarray'>
C的大小:(1, 5),D的大小:(5, 1)
【结果说明】:
带有双重括号的 C 为行向量,D 为列向量。
在 NumPy 中用 array()
函数生成的一维数组仅有一对方括号,而实际向量有两层方括号(属于二维数组)。 若 A=[1, 2, 3, 4, 5],则生成的是一维数组。
【代码】:
import numpy as np
A = [1, 2, 3, 4, 5]
C = np.array(A)
print("C = ", C)
print("A的类型:%s" % (type(A)))
print("C的类型:%s,C的大小:%s" % (type(C), np.shape(C)))
【运行结果】:
C = [1 2 3 4 5]
A的类型:<class 'list'>
C的类型:<class 'numpy.ndarray'>,C的大小:(5,)
【结果说明】:
输出的 C 只有一对
[
]
\left [ \: \right ]
[], 所以 C 为一维数组,而不是一个行向量或者列向量,C 的大小为 (5 ,) 也说明 C 为一维数组,当需要向量时可以通过 reshape()
函数改变矩阵的维度生成向量。
利用 np.random.random((1, n))
函数或者 np.random.random((n, 1))
函数创建元素值为随机浮点数的
n
n
n 维行向量或
n
n
n 维列向量,利用 np.random.randint()
函数创建元素值为整数的行向量或列向量。
【代码】:
import numpy as np
arr1 = np.random.random((1, 3)) # 默认范围为0~1
arr2 = np.random.random((3, 1)) # 默认范围为0~1
arr3 = np.random.randint(3, 30, size=[1, 3])
arr4 = np.random.randint(3, 30, size=[3, 1])
print("创建的三维行向量(由随机浮点数组成): \n", arr1)
print("创建的三维列向量(由随机浮点数组成): \n", arr2)
print("创建的三维行向量(由[3,30)随机整数组成): \n", arr3)
print("创建的三维列向量(由[3,30)随机整数组成): \n", arr4)
【运行结果】:
创建的三维行向量(由随机浮点数组成):
[[0.18722335 0.12386824 0.72657313]]
创建的三维列向量(由随机浮点数组成):
[[0.0128226 ]
[0.57106029]
[0.5744715 ]]
创建的三维行向量(由[3,30)随机整数组成):
[[11 14 26]]
创建的三维列向量(由[3,30)随机整数组成):
[[ 7]
[10]
[21]]
【结果说明】:
行向量和列向量的维度通过 size
设置,注意 size
的形式,可以为列表或元组。
【注意】np.random.random(n) 生成含有 n 个随机浮点数的一维数组,而不是向量。
【代码】:
import numpy as np
A = np.random.random(3)
print("A =", A)
print("A.shape =", A.shape)
【运行结果】:
A = [0.92550933 0.49315094 0.09091079]
A.shape = (3,)
【结果说明】:
A是一维数组,而不是一个行向量或者列向量,在计算中如果生成这种数据形式,可能会给向量计算带来难以调试的 bug,因此可以通过 reshape()
函数生成向量。
首先以列表或元组给出向量的分量值,然后通过 np.array()
函数生成一维数组,再通过 reshape()
函数中的数组创建指定维度的行向量或列向量。
【代码】:
import numpy as np
A = [1, 2, 3, 4, 5]
B = np.array(A) # 一维数组,共5个元素
C = B.reshape(1, 5) # 转换成5维行向量
D = B.reshape(5, 1) # 转换成5维列向量
print("一维数组B: ", B)
print("行向量C: ", C)
print("列向量D: ", D)
print("B的维度: ", B.shape)
print("C的维度: ", C.shape)
print("D的维度: ", D.shape)
【运行结果】:
一维数组B: [1 2 3 4 5]
行向量C: [[1 2 3 4 5]]
列向量D: [[1]
[2]
[3]
[4]
[5]]
B的维度: (5,)
C的维度: (1, 5)
D的维度: (5, 1)
【提示】:
通过 reshape(1, - 1)
或 reshape( -1, 1 )
,NumPy 自动计算出列数或行数。可用 C = B.reshape(1, -1)
或 D = B.reshape(-1, 1 )
分别代替 C = B.reshape(1, 5)
和 D = B.reshape(5, 1)
。
元素值具有一定规律的矩阵称为特殊的矩阵。在机器学习中一些特殊类型的矩阵和向量有特别的用处。
1. 零矩阵
元素全为 0 的矩阵,称为零矩阵,记作 O \mathbf{O} O。
如:
O
=
[
0
0
0
0
0
0
0
0
0
0
0
0
]
\mathbf{O}=
在 NumPy 中,通过 np.zeros() 函数创建零矩阵,只需传入一个表示形状的元组即可。
【代码】:
import numpy as np
arr1 = np.zeros(10)
arr2 = np.zeros((3, 4))
arr3 = np.array([np.zeros(10)])
print("通过zeros函数创建的零数组arr1: ", arr1)
print("通过zeros函数创建的零矩阵arr2: ", arr2)
print("通过zeros函数创建的零向量arr3: ", arr3)
print("arr1的形状: ", arr1.shape)
print("arr2的形状: ", arr2.shape)
print("arr3的形状: ", arr3.shape)
【运行结果】:
通过zeros函数创建的零数组arr1: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
通过zeros函数创建的零矩阵arr2: [[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
通过zeros函数创建的零向量arr3: [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
arr1的形状: (10,)
arr2的形状: (3, 4)
arr3的形状: (1, 10)
2. 方阵
行列数相等且都为 n n n 的矩阵称为 n n n 阶方阵,记作 A n \mathbf{A_{n}} An。
如:
A
n
=
[
80
75
75
78
98
70
85
84
90
75
90
90
88
70
82
89
]
\mathbf{A_{n}}=
例如,创建一个3阶方阵,元素值为1~16的随机整数。
【代码】:
import numpy as np
arr = np.random.randint(1, 16, size=[3, 3])
print("元素值为1~16随机整数的3阶方阵: \n", arr)
【运行结果】:
元素值为1~16随机整数的3阶方阵:
[[ 1 2 12]
[ 3 3 11]
[ 6 11 11]]
3. 单位矩阵
主对角线上全为 1, 其他位置都为 0 的方阵称为单位矩阵,常记作 E \mathbf{E} E 或者 I \mathbf{I} I。
如:
E
=
[
1
0
⋯
0
0
1
⋯
0
⋮
⋮
⋱
⋮
0
0
⋯
1
]
n
×
n
\mathbf{E}=
单位矩阵与矩阵的乘积满足: A m × n ⋅ E n × n = A m × n , E m × m × A m × n = A m × n \mathbf{A}_{m\times n}\cdot \mathbf{E}_{n\times n} = \mathbf{A}_{m\times n}, \; \mathbf{E}_{m\times m} \times \mathbf{A}_{m\times n} = \mathbf{A}_{m\times n} Am×n⋅En×n=Am×n,Em×m×Am×n=Am×n
单位矩阵在矩阵的乘法中具有特殊作用,如同数乘法中的1。
在 NumPy 中,可以通过 np.eye()
函数或者 np.identity()
函数创建单位矩阵。
【代码】:
import numpy as np
E1 = np.eye(3)
E2 = np.identity(3)
print("通过eye函数创建的3阶单位矩阵E1: \n", E1)
print("通过identity函数创建的3阶单位矩阵E2: \n", E2)
【运行结果】:
通过eye函数创建的3阶单位矩阵E1:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
通过identity函数创建的3阶单位矩阵E2:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
4. 对角矩阵
只在主对角线上含有非零元素,其他位置都为 0 的方阵称为对角矩阵。
如:
A
=
[
a
11
0
⋯
0
0
a
22
⋯
0
⋮
⋮
⋱
⋮
0
0
⋯
a
n
n
]
n
×
n
\mathbf{A}=
对角矩阵常用于矩阵分解。
(1)在 NumPy 中,可以通过 np.diag()
函数创建对角矩阵。
当以元组或列表的形式给出对角线元素,使用 np.diag()
函数可以创建以这几个元素为对角线的方阵。np.diag()
函数也可以作用于方阵,获得方阵的对角线元素。
【代码】:
import numpy as np
a = [1, 2, 3] # 对角线元素
arr1 = np.diag(a) # 创建对角矩阵
print("创建主对角线元素为1,2,3的对角矩阵arr1: \n", arr1)
arr2 = np.diag(arr1)
print("获取矩阵arr1的对角线元素: \n", arr2)
print("arr2的类型: ", arr2.shape)
【运行结果】:
创建主对角线元素为1,2,3的对角矩阵arr1:
[[1 0 0]
[0 2 0]
[0 0 3]]
获取矩阵arr1的对角线元素:
[1 2 3]
arr2的类型: (3,)
【结果说明】:
可以看出,arr2 的类型为一维数组。
(2)根据矩阵的对角线元素生成对角矩阵,只需要嵌套两个 np.diag()
函数即可。
【代码】:
import numpy as np
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
C = np.array(A)
arr = np.diag(np.diag(C))
print("原始矩阵C: \n", C)
print("根据C的对角线元素生成的对角矩阵: \n", arr)
【运行结果】:
原始矩阵C:
[[1 2 3]
[4 5 6]
[7 8 9]]
根据C的对角线元素生成的对角矩阵:
[[1 0 0]
[0 5 0]
[0 0 9]]
(3)当 np.diag()
函数作用于矩阵(不一定为方阵)时可以获得矩阵的对角线元素。
【代码】:
import numpy as np
C = np.array([[1, 2, 3], [4, 5, 6]])
arr = np.diag(C)
print("获取矩阵C的对角线元素: \n", arr)
【运行结果】:
获取矩阵C的对角线元素:
[1 5]
5. 上三角矩阵
主对角线上非 0,主对角线下都是 0 的方阵称为上三角矩阵。
如:
A
=
[
a
11
a
12
⋯
a
1
n
0
a
22
⋯
a
2
n
⋮
⋮
⋱
⋮
0
0
⋯
a
n
n
]
n
×
n
\mathbf{A}=
6. 下三角矩阵
主对角线下非 0,主对角线上都是 0 的方阵称为下三角矩阵。
如:
A
=
[
a
11
0
⋯
0
a
21
a
22
⋯
0
⋮
⋮
⋱
⋮
a
n
1
a
n
2
⋯
a
n
n
]
n
×
n
\mathbf{A}=
通过 np.triu(matrix, k)
函数可以获取矩阵 matrix 的上半部分,
k
=
0
k=0
k=0 代表对角线存在于处理后的矩阵中,
k
=
1
k=1
k=1 代表处理后的矩阵不包括对角线元素。通过 np.tril(matrix, k)
函数可以获取矩阵 matrix的下半部分,
k
=
0
k=0
k=0 代表对角线存在于处理后的矩阵中,
k
=
−
1
k=-1
k=−1 代表处理后的矩阵不包括对角线元素。
【代码】:
import numpy as np
A = np.array([[1, 2, 3, 2], [4, 5, 6, 3], [7, 8, 9, 4], [3, 5, 6, 8]])
upper_A = np.triu(A, 0)
low_A = np.tril(A, 0)
print("A矩阵: \n", A)
print("A的上三角矩阵: \n", upper_A)
print("A的下三角矩阵: \n", low_A)
【运行结果】:
A矩阵:
[[1 2 3 2]
[4 5 6 3]
[7 8 9 4]
[3 5 6 8]]
A的上三角矩阵:
[[1 2 3 2]
[0 5 6 3]
[0 0 9 4]
[0 0 0 8]]
A的下三角矩阵:
[[1 0 0 0]
[4 5 0 0]
[7 8 9 0]
[3 5 6 8]]
7. 对称矩阵
满足 a i j = a j i a_{ij}=a_{ji} aij=aji 的方阵称为对称矩阵,也就是元素关于主对角线对称。
如矩阵
A
A
A 为四阶对称矩阵:
A
=
[
2
0
1
−
6
0
3
8
4
1
8
−
1
7
−
6
4
7
5
]
4
×
4
A =
8. 同型矩阵
行列数相同的两个矩阵称为同型矩阵。
如:
A
=
[
1
−
6
8
4
−
1
7
7
5
]
4
×
2
,
B
=
[
2
0
0
3
1
8
−
6
4
]
4
×
2
A =
通过比较矩阵 A A A 和矩阵 B B B 的 s h a p e shape shape 值是否相同,可判断 A A A 和 B B B 是否同型。
【代码】:
import numpy as np
A = [3, 4]
B = [4, 3]
arr1 = np.random.randint(3, 9, size=A) # arr1为3x4矩阵
arr2 = np.random.randint(10, 30, size=A) # arr2为3x4矩阵
arr3 = np.random.randint(50, 100, size=B) # arr3为4x3矩阵
print("arr1 = \n", arr1)
print("arr2 = \n", arr2)
print("arr3 = \n", arr3)
print("arr1与arr2是否同型: ", np.shape(arr1) == np.shape(arr2))
print("arr1与arr3是否同型: ", np.shape(arr1) == np.shape(arr3))
【运行结果】:
arr1 =
[[3 6 6 4]
[5 5 5 5]
[7 7 4 3]]
arr2 =
[[16 18 14 29]
[19 24 17 28]
[29 22 15 29]]
arr3 =
[[85 88 81]
[77 94 81]
[82 88 71]
[52 71 96]]
arr1与arr2是否同型: True
arr1与arr3是否同型: False
9. 矩阵相等
若 A A A 与 B B B 为同型矩阵且对应位置的各个元素相同,则称矩阵 A A A 和 B B B 相等。
在 NumPy 中,可以根据 np.allclose()
函数检验矩阵是否相等,返回值为 True 代表两个矩阵相等,False 代表两个矩阵不等。
【代码】:
import numpy as np
A = np.array([[1, 1, 1], [1, 2, 4], [1, 3, 9]])
B = np.array([2, 3, 5])
C = np.array([[1, 1, 1], [1, 2, 4], [1, 3, 9]])
# 利用allclose()检验矩阵是否相等,True代表相等,False代表不等。
print("A和B是否相等: ", np.allclose(A, B))
print("A和C是否相等: ", np.allclose(A, C))
【运行结果】:
A和B是否相等: False
A和C是否相等: True
当将数据用矩阵表示后,可以实现矩阵之间的相互运算。矩阵常见的操作有加减法运算、数乘、乘法、乘方等运算,但是没有除法运算。这些运算都有严格的定义,在机器学习中会经常用到。
设
A
A
A 和
B
B
B 是两个
m
×
n
m \times n
m×n 的同型矩阵,
A
=
(
a
i
j
)
A = \left ( a_{ij} \right )
A=(aij),
B
=
(
b
i
j
)
B = \left ( b_{ij} \right )
B=(bij)。 只有同型矩阵才可以作加减法运算。
A
±
B
=
[
a
11
±
b
11
a
12
±
b
12
⋯
a
1
n
±
b
1
n
a
21
±
b
21
a
22
±
b
22
⋯
a
2
n
±
b
2
n
⋮
⋮
⋱
⋮
a
m
1
±
b
m
1
a
m
2
±
b
m
2
⋯
a
m
n
±
b
m
n
]
m
×
n
\mathbf{A\pm B}=
在 NumPy 中,矩阵的加减法对 matrix 类型和 array 类型是通用的。
【代码】:
import numpy as np
A = [[1, 2, 3], [3, 2, 1]]
B = [[6, 8, 12], [10, 5, 12]]
C = np.array(A)
D = np.array(B)
print("C + D = \n", C + D)
print("C - D = \n", C - D)
【运行结果】:
C + D =
[[ 7 10 15]
[13 7 13]]
C - D =
[[ -5 -6 -9]
[ -7 -3 -11]]
设数
λ
\lambda
λ 与矩阵
A
A
A 的乘积记作
λ
A
\lambda A
λA 或
A
λ
A \lambda
Aλ。 规定:
λ
A
=
A
λ
=
[
λ
a
11
λ
a
12
⋯
λ
a
1
n
λ
a
21
λ
a
22
⋯
λ
a
2
n
⋮
⋮
⋱
⋮
λ
a
m
1
λ
a
m
2
⋯
λ
a
m
n
]
m
×
n
\lambda A = A \lambda =
在 NumPy 中,矩阵的数乘对 matrix 类型和 array 类型是通用的。
【代码】:
import numpy as np
A = [[1, 2, 3], [4, 5, 6]]
C = np.array(A)
print("矩阵的数乘:2C = \n", 2*C)
【运行结果】:
矩阵的数乘:2C =
[[ 2 4 6]
[ 8 10 12]]
设矩阵 A m × p A_{m \times p} Am×p 和 B p × n B_{p \times n} Bp×n,称 m × n m \times n m×n 阶的矩阵 C C C 为矩阵 A A A 与 B B B 的乘积,记作 C m × n = A m × p × B p × n C_{m \times n} = A_{m \times p} \times B_{p \times n} Cm×n=Am×p×Bp×n,简写为: C = A B C=AB C=AB,运算公式如下: C i j = ∑ k = 1 p a i k b k j = a i 1 b 1 j + a i 2 b 2 j + ⋯ + a i p b p j C_{ij} = \sum_{k=1}^{p} a_{ik}b_{kj} = a_{i1}b_{1j} + a_{i2}b_{2j} + \dots + a_{ip}b_{pj} Cij=k=1∑paikbkj=ai1b1j+ai2b2j+⋯+aipbpj
结果矩阵 C C C 的第 i i i 行与第 j j j 列交叉位置的值,等于矩阵 A A A 第 i i i 行与矩阵 B B B 第 j j j 列对应位置的每个值的乘积之和。如:
注意,第一个矩阵的列数和第二个矩阵的行数相同时,两个矩阵才可以进行乘法运算。结果矩阵的行数与第 1 个矩阵的行数相同,结果矩阵的列数与第 2 个矩阵的列数相同。
(1)矩阵的乘法运算具有以下性质。
∙
\bullet
∙ 乘法不满足交换律, 即
A
B
≠
B
A
AB \ne BA
AB=BA。
∙
\bullet
∙
(
A
B
)
C
=
A
(
B
C
)
\left ( AB \right ) C = A \left ( BC \right )
(AB)C=A(BC)。
∙
\bullet
∙
A
(
B
+
C
)
=
A
B
+
A
C
A \left ( B+C \right ) = AB + AC
A(B+C)=AB+AC。
∙
\bullet
∙
(
B
+
C
)
A
=
B
A
+
C
A
\left ( B+C \right )A = BA + CA
(B+C)A=BA+CA。
∙
\bullet
∙
λ
A
B
=
(
λ
A
)
B
=
A
(
λ
B
)
\lambda AB = \left ( \lambda A \right ) B = A \left ( \lambda B \right )
λAB=(λA)B=A(λB)。
在 NumPy 中,对于 array 类型和 matrix 类型, 实现矩阵乘法的方法不同。
对于 array 类型,可以通过 np.dot()
函数或 np.matmul()
函数实现矩阵的乘积,对于一维数组,可实现两个数组对应元素的乘积之和。
【代码】:
import numpy as np
# 矩阵乘法
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[1, 2],[3, 4], [5, 6]])
C = np.dot(A, B)
D = A.dot(B)
print("C = \n", C)
print("D = \n", D)
# 一维数组乘法
one_vec1 = np.array([1, 2, 3])
one_vec2 = np.array([4, 5, 6])
one_multi_result = np.dot(one_vec1, one_vec2)
print("one_multi_result = ", one_multi_result)
【运行结果】:
C =
[[22 28]
[49 64]]
D =
[[22 28]
[49 64]]
one_multi_result = 32
【结果说明】:
np.dot(A, B)
和 A.dot(B)
计算的值相同。dot 运算可以对一维数组使用,但是不能对向量直接相乘,如运行下列代码将报错:
【代码】:
one_vec1 = np.array([[1, 2, 3]])
one_vec2 = np.array([[4, 5, 6]])
one_multi_result = np.dot(one_vec1, one_vec2)
print("one_multi_result = ", one_multi_result)
【运行结果】:
ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)
(2)在 NumPy 中对于 array 类型可以采用两种方法实现两个同型矩阵中对应元素的相乘,一个是使用 np.multiply
函数,另外一个是使用
∗
*
∗。
【代码】:
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[7, 8, 9], [4, 7, 1]])
# 方法一:使用 * 实现A和B对应元素的乘积
C1 = A * B
print("C1 = \n", C1)
# 方法一:使用 np.multiply 实现A和B对应元素的乘积
C2 = np.multiply(A, B)
print("C2 = \n", C2)
【运行结果】:
C1 =
[[ 7 16 27]
[16 35 6]]
C2 =
[[ 7 16 27]
[16 35 6]]
(3)对 matrix 类型,可使用np.dot()
函数或
∗
*
∗ 做矩阵的乘法,使用 np.multiply()
函数实现同型矩阵对应元素的乘积。
【代码】:
import numpy as np
A = np.mat([[1, 2, 3], [4, 5, 6]])
B = np.mat([[1, 2], [3, 4], [5, 6]])
C = np.mat([[3, 2, 3], [5, 4, 6]])
# 方法一:使用 np.dot 实现A和B矩阵相乘
D1 = np.dot(A, B)
# 方法二:使用 * 实现A和B矩阵相乘
D2 = A * B
E = np.multiply(A, C)
print("D1 = \n", D1)
print("D2 = \n", D2)
print("E = \n", E)
【运行结果】:
D1 =
[[22 28]
[49 64]]
D2 =
[[22 28]
[49 64]]
E =
[[ 3 4 9]
[20 20 36]]
矩阵和向量的乘法是机器学习中最重要的操作之一。
(1)设矩阵 A m × n A_{m \times n} Am×n 和 n n n 维列向量 X X X 相乘,可以按照矩阵和矩阵的乘法进行运算,结果为 m m m 维列向量,即 m × 1 m \times 1 m×1 阶矩阵。
【代码】:
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]])
vector = np.array([[7], [8], [9]])
result = np.dot(A, vector)
print("矩阵与列向量的乘法: \n", result)
【运行结果】:
矩阵与列向量的乘法:
[[ 50]
[122]]
(2)设 m m m 维行向量 X X X 和 矩阵 A m × n A_{m \times n} Am×n 相乘,结果为 n n n 维行向量,即 1 × n 1 \times n 1×n 阶矩阵。
【代码】:
import numpy as np
vector = np.array([[7, 8]])
A = np.array([[1, 2, 3], [4, 5, 6]])
result = np.dot(vector, A)
print("行向量与矩阵的乘法: \n", result)
【运行结果】:
行向量与矩阵的乘法:
[[39 54 69]]
只有方阵才能进行乘方运算, A 1 = A , A 2 = A A , A k + 1 = A K A = A A K A^{1} = A, A^{2} = AA, A^{k+1}=A^{K}A = AA^{K} A1=A,A2=AA,Ak+1=AKA=AAK, k k k 为正整数, A K A^{K} AK 就是 k k k 个 A A A 相乘。
对 array 类型, 矩阵的乘方需要通过多次 dot 运算得到。对 matrix 类型,可以通过 ∗ ∗ n **n ∗∗n 得到,但要求必须是方阵; 对 array 类型, ∗ ∗ n **n ∗∗n 是每个元素的 n n n 次方,不要求是方阵。
【代码】:
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
A_array = np.array(A)
A_matrix = np.mat(A)
B = A_array.dot(A_array).dot(A_array)
C = A_matrix**3
D = A_array**3
print("array的三次方: \n", B)
print("matrix的三次方: \n", C)
print("array元素的三次方: \n", D)
【运行结果】:
array的三次方:
[[ 468 576 684]
[1062 1305 1548]
[1656 2034 2412]]
matrix的三次方:
[[ 468 576 684]
[1062 1305 1548]
[1656 2034 2412]]
array元素的三次方:
[[ 1 8 27]
[ 64 125 216]
[343 512 729]]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。