{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "8d3c680b", "metadata": {}, "source": [ "# 线性代数模块\n", "\n", "scipy.linalg是SciPy中负责线性代数计算的模块。NumPy也有numpy.linalg模块,不过建议使用scipy.linalg,原因有二:\n", "- scipy.linalg包含numpy.linalg中的所有函数,同时还包含了很多numpy.linalg中没有的函数;\n", "- scipy.linalg默认使用线性代数库BLAS/LAPACK等对运算进行加速,而在numpy.linalg中,这些加速是需要自己配置,不是默认设置:" ] }, { "cell_type": "code", "execution_count": 1, "id": "aa0ef52c", "metadata": {}, "outputs": [], "source": [ "import numpy.linalg" ] }, { "cell_type": "code", "execution_count": 2, "id": "1cba1a1a", "metadata": {}, "outputs": [], "source": [ "import scipy.linalg" ] }, { "cell_type": "code", "execution_count": 3, "id": "b65ef6f6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "34" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(dir(numpy.linalg))" ] }, { "cell_type": "code", "execution_count": 4, "id": "4a139a95", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "156" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(dir(scipy.linalg))" ] }, { "cell_type": "code", "execution_count": 5, "id": "c920896b", "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "code", "execution_count": 6, "id": "571cb2e1", "metadata": {}, "outputs": [], "source": [ "from scipy import linalg" ] }, { "cell_type": "markdown", "id": "79b71214", "metadata": {}, "source": [ "## 基本的矩阵操作" ] }, { "attachments": {}, "cell_type": "markdown", "id": "969794d4", "metadata": {}, "source": [ "在NumPy中,矩阵有两种表示方法:矩阵类型和二维数组类型。\n", "\n", "矩阵类型可以用`np.mat()`或者`np.matrix()`创建:" ] }, { "cell_type": "code", "execution_count": 7, "id": "fa1f33c1", "metadata": {}, "outputs": [], "source": [ "A = np.mat(\"[1, 2; 3, 4]\")" ] }, { "cell_type": "code", "execution_count": 8, "id": "094e37a6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "code", "execution_count": 9, "id": "d221a93a", "metadata": {}, "outputs": [], "source": [ "A = np.matrix(\"[1, 2; 3, 4]\")" ] }, { "cell_type": "code", "execution_count": 10, "id": "ffb1da83", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "attachments": {}, "cell_type": "markdown", "id": "2e135a8f", "metadata": {}, "source": [ "转置矩阵为:" ] }, { "cell_type": "code", "execution_count": 11, "id": "5544773c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[1, 3],\n", " [2, 4]])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.T" ] }, { "cell_type": "markdown", "id": "755aa7fa", "metadata": {}, "source": [ "矩阵的逆矩阵:" ] }, { "cell_type": "code", "execution_count": 12, "id": "d895134e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[-2. , 1. ],\n", " [ 1.5, -0.5]])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.I" ] }, { "cell_type": "markdown", "id": "e19f8bcc", "metadata": {}, "source": [ "矩阵乘法:" ] }, { "cell_type": "code", "execution_count": 13, "id": "4a6607e0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[1.00000000e+00, 0.00000000e+00],\n", " [1.11022302e-16, 1.00000000e+00]])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.I * A" ] }, { "cell_type": "code", "execution_count": 14, "id": "23bd32db", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "matrix([[1.0000000e+00, 0.0000000e+00],\n", " [8.8817842e-16, 1.0000000e+00]])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * A.I" ] }, { "attachments": {}, "cell_type": "markdown", "id": "3509019e", "metadata": {}, "source": [ "数组类型也可以完成类似的操作:" ] }, { "cell_type": "code", "execution_count": 15, "id": "89a53b06", "metadata": {}, "outputs": [], "source": [ "A = np.array([[1, 2], [3, 4]])" ] }, { "cell_type": "code", "execution_count": 16, "id": "eab9d269", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "markdown", "id": "a504404a", "metadata": {}, "source": [ "转置:" ] }, { "cell_type": "code", "execution_count": 17, "id": "9b50a2c0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 3],\n", " [2, 4]])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.T" ] }, { "cell_type": "markdown", "id": "411b9f36", "metadata": {}, "source": [ "其逆矩阵可以用`linalg.inv()`函数计算:" ] }, { "cell_type": "code", "execution_count": 18, "id": "82bc4036", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.0000000e+00, 0.0000000e+00],\n", " [8.8817842e-16, 1.0000000e+00]])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.dot(linalg.inv(A))" ] }, { "cell_type": "code", "execution_count": 19, "id": "9a52cc39", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.0000000e+00, 0.0000000e+00],\n", " [8.8817842e-16, 1.0000000e+00]])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A @ linalg.inv(A)" ] }, { "cell_type": "code", "execution_count": 20, "id": "e871f638", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.00000000e+00, 0.00000000e+00],\n", " [1.11022302e-16, 1.00000000e+00]])" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.inv(A) @ A" ] }, { "attachments": {}, "cell_type": "markdown", "id": "250c4d3f", "metadata": {}, "source": [ "`scipy.linalg`也可以作用在矩阵类型上,返回的还是一个数组:" ] }, { "cell_type": "code", "execution_count": 21, "id": "0b0ea345", "metadata": {}, "outputs": [], "source": [ "A = np.matrix([[1, 2], [3, 4]])" ] }, { "cell_type": "code", "execution_count": 22, "id": "fcb3602e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-2. , 1. ],\n", " [ 1.5, -0.5]])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.inv(A)" ] }, { "cell_type": "markdown", "id": "f9397b1c", "metadata": {}, "source": [ "矩阵类型的使用比较少,通常都用数组类型替代矩阵类型进行计算。" ] }, { "cell_type": "markdown", "id": "e297badc", "metadata": {}, "source": [ "## 线性方程组的求解" ] }, { "attachments": {}, "cell_type": "markdown", "id": "a24b6a4d", "metadata": {}, "source": [ "考虑下列方程组:\n", "```\n", " x + 3y + 5z = 10\n", "2x + 5y - z = 8\n", "2x + 3y + 8z = 3\n", "```\n", "\n", "矩阵形式为:\n", "$$\n", "\\left[\n", "\\begin{array}{1}\n", "1 & 3 & 5 \\\\\n", "2 & 5 & -1 \\\\\n", "2 & 3 & 8 \\\\\n", "\\end{array}\n", "\\right]\n", "\\left[\n", "\\begin{array}{1}\n", "x \\\\\n", "y \\\\\n", "z \\\\\n", "\\end{array}\n", "\\right]\n", "=\n", "\\left[\n", "\\begin{array}{1}\n", "10 \\\\\n", "8 \\\\\n", "3 \\\\\n", "\\end{array}\n", "\\right]\n", "$$\n", "\n", "其解为:\n", "$$\n", "\\left[\n", "\\begin{array}{1}\n", "x \\\\\n", "y \\\\\n", "z \\\\\n", "\\end{array}\n", "\\right]\n", "=\n", "\\left[\n", "\\begin{array}{1}\n", "1 & 3 & 5 \\\\\n", "2 & 5 & -1 \\\\\n", "2 & 3 & 8 \\\\\n", "\\end{array}\n", "\\right]^{-1}\n", "\\left[\n", "\\begin{array}{1}\n", "10 \\\\\n", "8 \\\\\n", "3 \\\\\n", "\\end{array}\n", "\\right]\n", "$$\n", "\n", "故:" ] }, { "cell_type": "code", "execution_count": 23, "id": "a631aeb7", "metadata": {}, "outputs": [], "source": [ "A = np.array([[1, 3, 5],\n", " [2, 5, -1],\n", " [2, 3, 8]])" ] }, { "cell_type": "code", "execution_count": 24, "id": "3017b816", "metadata": {}, "outputs": [], "source": [ "b = np.array([10, 8, 3])" ] }, { "cell_type": "markdown", "id": "af0e6885", "metadata": {}, "source": [ "解:" ] }, { "cell_type": "code", "execution_count": 25, "id": "64da5739", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "array([-8.83870968, 5.25806452, 0.61290323])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.inv(A) @ b" ] }, { "attachments": {}, "cell_type": "markdown", "id": "3ff7b6d3", "metadata": {}, "source": [ "也可以直接使用`linalg.solve()`函数,直接求解这个方程:" ] }, { "cell_type": "code", "execution_count": 26, "id": "349caf78", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-8.83870968, 5.25806452, 0.61290323])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.solve(A, b)" ] }, { "cell_type": "markdown", "id": "19f5a3b0", "metadata": {}, "source": [ "## 行列式的计算:" ] }, { "cell_type": "markdown", "id": "00a11f84", "metadata": {}, "source": [ "`linalg.det()`函数可以计算矩阵的行列式:" ] }, { "cell_type": "code", "execution_count": 27, "id": "73f30cf7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-31.000000000000007" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.det(A)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "a392795e", "metadata": {}, "source": [ "行列式非零表示矩阵是可逆的。逆矩阵的行列式与矩阵的行列式满足相乘等于1的关系:" ] }, { "cell_type": "code", "execution_count": 28, "id": "e2989093", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-0.03225806451612903" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.det(linalg.inv(A))" ] }, { "cell_type": "code", "execution_count": 29, "id": "7762fa35", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0000000000000002" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.det(linalg.inv(A)) * linalg.det(A)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "e46a7a69", "metadata": {}, "source": [ "## 范数的计算" ] }, { "cell_type": "code", "execution_count": 30, "id": "9b9bf730", "metadata": {}, "outputs": [], "source": [ "A = np.array([[1, 2], [3, 4]])" ] }, { "attachments": {}, "cell_type": "markdown", "id": "db9beb30", "metadata": {}, "source": [ "默认情况下,`linalg.norm()`函数计算的是矩阵的Frobenius范数,该范数计算的是矩阵所有元素平方和的平方根:" ] }, { "cell_type": "code", "execution_count": 31, "id": "e09c0730", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.477225575051661" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A)" ] }, { "cell_type": "code", "execution_count": 32, "id": "658a1746", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.477225575051661" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, \"fro\")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "a0d0a4a5", "metadata": {}, "source": [ "可以通过`linalg.norm()`函数中的第二个参数,来修改矩阵范数的计算方法。例如,矩阵的1范数,计算的是矩阵中每列元素的和的最大值:" ] }, { "cell_type": "code", "execution_count": 33, "id": "affe6ca1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6.0" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, 1)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "0d8fca3b", "metadata": {}, "source": [ "矩阵的-1范数,计算的是矩阵中每列元素的和的最小值:" ] }, { "cell_type": "code", "execution_count": 34, "id": "8eed8d80", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.0" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, -1)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "91357c89", "metadata": {}, "source": [ "矩阵的2范数,计算的是矩阵的最大奇异值:" ] }, { "cell_type": "code", "execution_count": 35, "id": "d0fa7c53", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.464985704219043" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, 2)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "b3421820", "metadata": {}, "source": [ "矩阵的-2范数,计算的是矩阵的最小奇异值:" ] }, { "cell_type": "code", "execution_count": 36, "id": "14389d34", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.36596619062625746" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, -2)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "da8e92f7", "metadata": {}, "source": [ "矩阵的正无穷范数,计算的是矩阵中每行元素的和的最大值:" ] }, { "cell_type": "code", "execution_count": 37, "id": "18293ca2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7.0" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, np.inf)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "6c6ea89e", "metadata": {}, "source": [ "矩阵的负无穷范数,计算的是矩阵中每行元素的和的最小值:" ] }, { "cell_type": "code", "execution_count": 38, "id": "055a13b9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(A, -np.inf)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "b99a6ae5", "metadata": {}, "source": [ "`linalg.norm()`函数也可以用来计算向量的范数(也称模):" ] }, { "cell_type": "code", "execution_count": 39, "id": "5b01a21d", "metadata": {}, "outputs": [], "source": [ "b = np.array([10, 8, 3])" ] }, { "attachments": {}, "cell_type": "markdown", "id": "a3ffeddd", "metadata": {}, "source": [ "对于向量来说,linalg.norm()函数默认是向量的2范数,即计算向量元素的平方和的平方根:" ] }, { "cell_type": "code", "execution_count": 40, "id": "40c8835e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "13.152946437965905" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(b)" ] }, { "cell_type": "code", "execution_count": 41, "id": "0bbce740", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "13.152946437965905" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "linalg.norm(b, 2)" ] }, { "cell_type": "markdown", "id": "3e57bf3d", "metadata": {}, "source": [ "## 特征值分解" ] }, { "attachments": {}, "cell_type": "markdown", "id": "35edb52d", "metadata": {}, "source": [ "对于方阵A,特征值λ和特征向量v满足:`Av=λv`。函数`linalg.eig()`可以用来求解特征值和特征向量:" ] }, { "cell_type": "code", "execution_count": 42, "id": "498f619f", "metadata": {}, "outputs": [], "source": [ "A = np.array([[1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9]])" ] }, { "cell_type": "code", "execution_count": 43, "id": "4b470fd3", "metadata": {}, "outputs": [], "source": [ "l, v = linalg.eig(A)" ] }, { "cell_type": "code", "execution_count": 44, "id": "7695b549", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.allclose(A.dot(v), l * v)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "a5623725", "metadata": {}, "source": [ "## 广义逆\n", "\n", "对于形状为m×n的矩阵A,可以用`linalg.pinv()`求解其广义逆。A的广义逆B满足:`A=ABA`,`B=ABA`:" ] }, { "cell_type": "code", "execution_count": 45, "id": "3e65543f", "metadata": {}, "outputs": [], "source": [ "A = np.array([[1, 2, 3],\n", " [4, 5, 6]])" ] }, { "cell_type": "code", "execution_count": 46, "id": "f7bc6b49", "metadata": {}, "outputs": [], "source": [ "B = linalg.pinv(A)" ] }, { "cell_type": "code", "execution_count": 47, "id": "ac4d5781", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.allclose(A, A @ B @ A)" ] }, { "cell_type": "code", "execution_count": 48, "id": "ea20c7e1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.allclose(B, B @ A @ B)" ] }, { "cell_type": "markdown", "id": "7463da00", "metadata": {}, "source": [ "## 奇异值分解" ] }, { "attachments": {}, "cell_type": "markdown", "id": "74047d9c", "metadata": {}, "source": [ "对于形状为m×n的矩阵A,其奇异值分解满足$A=U\\SigmaV^H$,矩阵Σ形状为M×N,主对角线上的元素被称为奇异值。U、V分别为M阶、N阶正交单位矩阵。\n", "\n", "函数`linalg.svd()`可以对矩阵进行奇异值分解:" ] }, { "cell_type": "code", "execution_count": 49, "id": "ffae72b3", "metadata": {}, "outputs": [], "source": [ "U, s, Vh = linalg.svd(A)" ] }, { "cell_type": "code", "execution_count": 50, "id": "be9437a5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-0.3863177 , -0.92236578],\n", " [-0.92236578, 0.3863177 ]])" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U" ] }, { "cell_type": "code", "execution_count": 51, "id": "1af28a78", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([9.508032 , 0.77286964])" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s" ] }, { "cell_type": "code", "execution_count": 52, "id": "b9174266", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-0.42866713, -0.56630692, -0.7039467 ],\n", " [ 0.80596391, 0.11238241, -0.58119908],\n", " [ 0.40824829, -0.81649658, 0.40824829]])" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Vh" ] }, { "cell_type": "markdown", "id": "cd3bdbca", "metadata": {}, "source": [ "从奇异值恢复矩阵$\\Sigma$:" ] }, { "cell_type": "code", "execution_count": 53, "id": "26907656", "metadata": {}, "outputs": [], "source": [ "S = linalg.diagsvd(s, 2, 3)" ] }, { "cell_type": "code", "execution_count": 54, "id": "c2878f35", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.allclose(A, U @ S @ Vh)" ] }, { "cell_type": "markdown", "id": "cd63330a", "metadata": {}, "source": [ "正交矩阵:" ] }, { "cell_type": "code", "execution_count": 55, "id": "c0ae03d2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1.00000000e+00, -8.49433239e-18],\n", " [-8.49433239e-18, 1.00000000e+00]])" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U @ U.T" ] }, { "cell_type": "code", "execution_count": 56, "id": "dec8f9d2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1.00000000e+00, 4.13108370e-17, 2.21870637e-17],\n", " [ 4.13108370e-17, 1.00000000e+00, -1.77008767e-16],\n", " [ 2.21870637e-17, -1.77008767e-16, 1.00000000e+00]])" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Vh @ Vh.T" ] }, { "cell_type": "code", "execution_count": null, "id": "f1d161a1", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.10" } }, "nbformat": 4, "nbformat_minor": 5 }