线性代数:矩阵基本运算

在本文中,我们将介绍矩阵的大部分基本运算,依次是矩阵的加减法、矩阵的标量乘法、矩阵与矩阵的乘法、求转置矩阵,以及深入了解矩阵的行列式运算。本文将不会涉及逆矩阵、矩阵的秩等概念,将来再探讨它们。

矩阵的加减法

矩阵的 加法减法 运算将接收两个矩阵作为输入,并输出一个新的矩阵。矩阵的加法和减法都是在分量级别上进行的,因此要进行加减的矩阵必须有着相同的维数。

为了避免重复编写加减法的代码,我们先创建一个可以接收运算函数的方法,这个方法将对两个矩阵的分量分别执行传入的某种运算。然后在加法、减法或者其它运算中直接调用它就行了:

class Matrix { // ... componentWiseOperation(func, { rows }) { const newRows = rows.map((row, i) => row.map((element, j) => func(this.rows[i][j], element)) ) return new Matrix(...newRows) } add(other) { return this.componentWiseOperation((a, b) => a + b, other) } subtract(other) { return this.componentWiseOperation((a, b) => a - b, other) }}const one = new Matrix( [1, 2], [3, 4])const other = new Matrix( [5, 6], [7, 8])console.log(one.add(other))// Matrix { rows: [ [ 6, 8 ], [ 10, 12 ] ] }console.log(other.subtract(one))// Matrix { rows: [ [ 4, 4 ], [ 4, 4 ] ] }复制代码

矩阵的标量乘法

矩阵的标量乘法与向量的缩放类似,就是将矩阵中的每个元素都乘上标量:

class Matrix {  // ...  scaleBy(number) {    const newRows = this.rows.map(row =>      row.map(element => element * number)    )    return new Matrix(...newRows)  }}const matrix = new Matrix(  [2, 3],  [4, 5])console.log(matrix.scaleBy(2))// Matrix { rows: [ [ 4, 6 ], [ 8, 10 ] ] }复制代码

矩阵乘法

AB 两个矩阵的维数是 兼容 的时候,就能对这两个矩阵进行矩阵乘法。所谓维数兼容,指的是 A 的列数与 B 的行数相同。矩阵的乘积 AB 是通过对 A 的每一行与矩阵 B 的每一列计算点积得到:

class Matrix { // ... multiply(other) { if (this.rows[0].length !== other.rows.length) { throw new Error('The number of columns of this matrix is not equal to the number of rows of the given matrix.') } const columns = other.columns() const newRows = this.rows.map(row => columns.map(column => sum(row.map((element, i) => element * column[i]))) ) return new Matrix(...newRows) }}const one = new Matrix( [3, -4], [0, -3], [6, -2], [-1, 1])const other = new Matrix( [3, 2, -4], [4, -3, 5])console.log(one.multiply(other))// Matrix {// rows:// [ [ -7, 18, -32 ],// [ -12, 9, -15 ],// [ 10, 18, -34 ],// [ 1, -5, 9 ] ]}复制代码

我们可以把矩阵乘法 AB 视为先后应用 AB 两个线性变换矩阵。为了更好地理解这种概念,可以看一看我们的linear-algebra-demo。

下图中黄色的部分就是对红色方块应用线性变换 C 的结果。而线性变换 C 就是矩阵乘法 AB 的结果,其中 A 是做相对于 y 轴进行反射的变换矩阵, B 是做剪切变换的矩阵。

如果在矩阵乘法中调换 AB 的顺序,我们会得到一个不同的结果,因为相当于先应用了 B 的剪切变换,再应用 A 的反射变换:

转置

转置矩阵 由公式 定义。换句话说,我们通过关于矩阵的对角线对其进行翻转来得到转置矩阵。需要注意的是,矩阵对角线上的元素不受转置运算影响。

class Matrix {  // ...  transpose() {    return new Matrix(...this.columns())  }}const matrix = new Matrix(  [0,  1,  2],  [3,  4,  5],  [6,  7,  8],  [9, 10, 11])console.log(matrix.transpose())// Matrix {//   rows: [//     [ 0, 3, 6, 9 ],//     [ 1, 4, 7, 10 ],//     [ 2, 5, 8, 11 ]//   ]// }复制代码

行列式运算

矩阵的 行列式 运算将计算矩阵中的所有系数,最后输出一个数字。准确地说,行列式可以描述一个由矩阵行构成的向量的相对几何指标(比如在欧式空间中的有向面积、体积等空间概念)。更准确地说,矩阵 A 的行列式相当于告诉你由 A 的行定义的方块的体积。 矩阵的行列式运算如下所示:

矩阵的行列式运算如下所示:

我们的方法可以计算任意大小矩阵(只要其行列的数量相同)的行列式:

class Matrix { // ... determinant() { if (this.rows.length !== this.rows[0].length) { throw new Error('Only matrices with the same number of rows and columns are supported.') } if (this.rows.length === 2) { return this.rows[0][0] * this.rows[1][1] - this.rows[0][1] * this.rows[1][0] } const parts = this.rows[0].map((coef, index) => { const matrixRows = this.rows.slice(1).map(row => [ ...row.slice(0, index), ...row.slice(index + 1)]) const matrix = new Matrix(...matrixRows) const result = coef * matrix.determinant() return index % 2 === 0 ? result : -result }) return sum(parts) }}const matrix2 = new Matrix( [ 0, 3], [-2, 1])console.log(matrix2.determinant())// 6const matrix3 = new Matrix( [2, -3, 1], [2, 0, -1], [1, 4, 5])console.log(matrix3.determinant())// 49const matrix4 = new Matrix( [3, 0, 2, -1], [1, 2, 0, -2], [4, 0, 6, -3], [5, 0, 2, 0])console.log(matrix4.determinant())// 20复制代码

行列式可以告诉我们变换时对象被拉伸的程度。因此我们可以将其视为线性变换改变面积的因子。为了更好地理解这个概念,请参考linear-algebra-demo:

在下图中,我们可以看到对红色的 1×1 方形进行线性变换后得到了一个 3×2 的长方形,面积从 1 变为了 6 ,这个数字与线性变换矩阵的行列式值相同。

如果我们应用一个剪切变换,可以看到方形会变成一个面积不变的平行四边形。因此,剪切变换矩阵的行列式值等于 1:

如果行列式的值是 负数 ,则说明应用线性变换后,空间被反转了。比如在下图中,我们可以看到变换前 在 的左边,而变换后 在 的右边。

如果变换的行列式为 0 ,则表示它会将所有空间都压缩到一条线或一个点上。也就是说,计算一个给定矩阵的行列式是否为 0,可以判断这个矩阵对应的线性变换是否会将对象压缩到更小的维度去。

在三维空间里,行列式可以告诉你体积缩放了多少:

变换行列式等于 0,意味着原来的空间会被完全压缩成体积为 0 的空间。如前文所说,如果在 2 维空间中变换的行列式为 0,则意味着变换的结果将空间压缩成了一条线或一个点;而在 3 维空间中变换的行列式为 0 意味着一个物体会被压扁成一个平面,如下图所示:

(0)

相关推荐

  • 【线性变换/矩阵及乘法】- 图解线性代数 03

    线性变换是线性空间中的运动, 而矩阵就是用来描述这种变换的工具. 这样说还是没有直观印象, 所以还是直接看图解的动画吧. 矩阵不仅仅只是数值的表: 其实表示了在该矩阵的作用下, 线性空间是怎样的变化, ...

  • 线性代数精华——矩阵的特征值与特征向量

    今天和大家聊一个非常重要,在机器学习领域也广泛使用的一个概念--矩阵的特征值与特征向量.[1] 我们先来看它的定义,定义本身很简单,假设我们有一个n阶的矩阵A以及一个实数lambda,使得我们可以找到 ...

  • 深度学习的数学基础 1. 线性代数:标量、向量、矩阵和张量

    原创编程圈子2020-12-15 11:04:24 一.标量.向量.矩阵与张量 1. 标量(scalar) 一个标量就是一个单独的数.标量用斜体表示. 标量通常使用小写变量名称. 在介绍标量时,会明确 ...

  • 矩阵就是方程组的系数吗?线性代数为何难学?

    说到矩阵,我们可能会立刻想到线性代数. 线性代数,不仅是大学理工科本科生的必修课,也是工作中十分有用的理论工具. 例如在机器学习.图像处理.机器人导航.自动控制等领域,线性代数都有着十分广泛的应用.理 ...

  • 线性代数精华——讲透矩阵的初等变换与矩阵的秩

    承志的算法课堂2020-01-07 14:10:00 这篇文章和大家聊聊矩阵的初等变换和矩阵的秩. 矩阵的初等变换这个概念可能在很多人听来有些陌生,但其实我们早在初中的解多元方程组的时候就用过它.只不 ...

  • 深度学习的数学基础1.线性代数:标量、向量、矩阵和张量

    https://m.toutiao.com/is/JWhm3cH/ 一.标量.向量.矩阵与张量 1. 标量(scalar) 一个标量就是一个单独的数.标量用斜体表示. 标量通常使用小写变量名称. 在介 ...

  • 线性代数:第二章 矩阵及其运算

    本讲义是自己上课所用幻灯片,里面没有详细的推导过程(笔者板书推导)只以大纲的方式来展示课上的内容,以方便大家下来复习. 本章主要介绍有关矩阵的知识,主要包括矩阵的基本运算(加法.数乘.乘法.乘幂.迹. ...

  • 【矮矩阵 / 长矩阵】- 图解线性代数 10

    矩阵乘法可以理解为一个特定的线性变换, 比如在 2x2 的可逆矩阵表示就是二维空间的(可逆)变换; 3x3 的可逆矩阵表示三维空间的变换. 这些都是 nxn 型的矩阵, 本节来看看更一般 mxn 矩阵 ...

  • 【矩阵的逆/逆变换】- 图解线性代数 06

    这次我们来看如何把矩阵 A 经过变换后的向量再还原回去. 观察下面如何从变换后的向量(-1.5, 2) 还原为向量 (1, 0.5) 的过程: 注意观察要点: 变换后线性空间还是完整的二维空间; 变换 ...

  • 【矩阵的乘积/复合变换】- 图解线性代数 05

    矩阵向量的乘积可以理解为将一个特定的线性变换作用在向量上, 本次我们先看几个特殊的矩阵下的变换以及矩阵矩阵的乘积. 零矩阵 即所有元素都是 0 的矩阵, 记为 O . 可以用下标来表示矩阵的大小: 零 ...