UIUC-CS357-数值方法-I-中文教科书-全-
UIUC CS357 数值方法 I 中文教科书(全)
原文:
cs357.cs.illinois.edu/textbook/译者:飞龙
笔记
这里是课程中每个主题的所有笔记。您也可以在侧边栏中访问相同的链接。
-
Python
-
误差与复杂度
-
浮点表示
-
舍入
-
泰勒级数
-
随机数生成器和蒙特卡洛方法
-
向量、矩阵和范数
-
求解线性方程的 LU 分解
-
稀疏矩阵
-
条件数
-
特征值与特征向量
-
马尔可夫链
-
有限差分法
-
求解非线性方程
-
优化
-
最小二乘拟合
-
奇异值分解 (SVD)
-
主成分分析 (PCA)
Python
查看幻灯片
如果你在这里看不到 PDF,请点击 这里 下载 PDF。
学习目标
-
熟悉 Python 3 语法
-
理解可变对象和不可变对象之间的区别
-
理解 NumPy 的用途,并了解 NumPy 数据类型的一些常见操作。
注意事项
-
记住,学习编程语言最有效的方法是实践!
-
Google 是任何编程语言的绝佳资源。
类型
就像任何其他语言一样,Python 中的变量可以存储不同类型的数据,例如 int、float 或 str。我们可以使用 type() 函数来查找表达式的类型。
示例
a = 2
b = 3.0
c = a + b
d = 2 * a
变量 c 和 d 的正确类型是什么?
答案
B.
在 Python 中,任何整数和浮点数之间的操作都会得到浮点数。因此,c 是浮点数。d 是整数,因为我们对两个整数进行了乘法运算。
名称和值
考虑以下示例:
a = [1, 2, 3]
b = a
在这种情况下,a 和 b 虽然是不同的变量,但它们并不是独立的实体。列表 [1, 2, 3] 是一个对象,变量名 a 和 b 都绑定到同一个列表上。
修改对象
现在让我们考虑另一个例子:
a = [1, 2, 3]
b = a
b.append(4)
b.append(4) 修改了对象列表,使得列表现在是 [1, 2, 3, 4]。我们知道 b 现在是 [1, 2, 3, 4],但变量名 a 发生了什么变化?
答案
因为 a 和 b 绑定到同一个列表,一旦列表被修改,它们将具有相同的值。
获取对象的 "id"
让我们看看如何使用内置的 Python 函数来查看 a 和 b 是否指向同一个对象。
# Since "a" and "b" are bounded to the same list object, they will have the same "id" print(id(a), id(b))
# The "is" keyword is an additional check to see if both variable names have the same "id" a is b
内存管理
为了回顾 Python 管理内存的方式,让我们看看以下示例:
# The following code will print "IS False" and "EQUAL True" because a and b are bounded to two different list objects.
# Hence, they don't have the same id but the contents of their data are the same.
a = [1, 2, 3]
b = [1, 2, 3]
print("IS ", a is b)
print("EQUAL", a == b)
# The following code is the case we've seen before.
# a and b are bounded to the same list object, and hence they'll have the same id.
a = [1, 2, 3]
b = a
可变和不可变对象
在 Python 中,对象分为 可变 和 不可变。可变对象在创建后可以被修改,包括列表、字典、NumPy 数组等。不可变对象一旦创建后就不能被修改,包括元组、字符串、浮点数等。
例如,
# A successful attempt to replace the first entry of the list
myList = [3, 5, 7]
myList[0] = 1
# The following two attempts will result in a TypeError: object does not suppoer item assignment
myTuple = (3, 5, 7)
myTuple[0] = 1
myString = "357"
myString[0] = '1'
列表
列表是可变对象的一个例子。让我们看看它在不同情况下是如何表现的:
# Again, the case we've seen before: a and b are bounded to the same list object
a = [1, 2, 3]
b = a
# Here, our variable a gets reassigned to a new object, but b is still bounded to the initial object
a = a + [4]
print(b)
print(a)
a is b # evaluates to False
# In this case, the object list is modified, however, a and b remain bounded to the object
a += [4]
print(b)
print(a)
a is b # evaluates to True
示例
以下代码片段中哪个会导致 print(a==c) -> True:
A:
a = ['hello','goodbye']
b = 'hey'
a.append(b)
c = a + [b]
B:
a = ['hello','goodbye']
b = 'hey'
c = a + [b]
a += b
C:
a = ['hello','goodbye']
b = 'hey'
c = a + [b]
a.append(b)
答案
C
A 是不正确的,因为 c 的列表中最终有两个 "hey" 元素。B 是不正确的,因为 a += b 将 "hey" 的每个字符都作为其自己的元素添加。因此,C 必须是正确的选择。
对象和命名
高级命名
让我们创建一些对象,并查看在接下来的代码片段中会发生什么:
fruit = 'apple'
lunch = []
lunch.append(fruit) # lunch = ['apple']
dinner = lunch # dinner = ['apple'], lunch = ['apple'] dinner.append('fish') # dinner = ['apple', 'fish'], lunch = ['apple', 'fish']
fruit = 'pear'
meals = [fruit, lunch, dinner]
print(meals) # meals = ['pear', ['apple', 'fish'], ['apple', 'fish']]
示例
以下代码片段的正确输出是什么?
John = 'computer_science'
Tim = John
Tim += ', math'
Anna = ['electrical']
Julie = Anna
Julie += ['physics']
print(John, Anna)
A: computer_science, math ['electrical', 'physics']
B: computer_science, math ['electrical']
C: computer_science ['electrical', 'physics']
D: computer_science ['electrical']
答案
C
在上面的代码片段中,由于 Python 中字符串是不可变的,John 和 Tim 指的是不同的对象,因此变量 John 等于'computer_science'。列表是可变的,所以 Julie 和 Anna 等于同一个列表:['electrical', 'physics']。因此,C 是正确的选择。
索引
索引在 Python 中通过多种方式遍历 for 循环非常重要。给定一个列表a,索引的格式遵循以下标准:a[i:j:k]。在这里,i是迭代的起始索引,j是迭代的停止索引(不包括),k是步长。
示例
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a[1::2][::-1]
上面的命令行输出是什么?
答案
\(\bf E\)
第一步是获取数组 a[1::2]的结果数组。在零索引数组中,起始索引是 1,步长是 1 直到数组的末尾(因为没有给出停止索引)。因此,结果数组是[1, 3, 5, 7, 9],我们现在将其称为数组 b。
最后一步是获取数组 b[::-1]的结果数组。没有给出起始或停止索引,但步长是-1。这意味着我们只需要反转数组 b,因为负步长意味着我们从数组的末尾开始迭代,而不是从开始迭代。因此,最终的数组将是[9, 7, 5, 3, 1],这等于答案选项 E。
控制流程
控制流程包括使用 for/while 循环遍历类似列表的对象,使用 if/else 块执行特定条件的逻辑,以及使用 break 和 continue 语句来控制何时退出 for 循环或移动到循环的下一个迭代。让我们看看这个简单示例:
# builds a list of the squares of integers below 50 divisible by 7
mylist = []
for i in range(50):
if i % 7 == 0:
mylist.append(i**2)
# does this using something called list comprehension, a concise and easy way to write the code block above
mylist = [i**2 for i in range(50) if i % 7 == 0]
print(mylist)
函数
定义函数
有时定义一个函数是有用的。这是通过使用关键字"def"后跟参数列表来完成的。以下是一个函数定义的基本示例:
# a function to return the area of a square def area(length):
return length ** 2
print(area(2))
这是关于函数定义的官方文档。
函数作用域
理解作用域的概念很重要。在函数内部创建的变量只能在该函数内部使用,因为它具有局部作用域。在 Python 代码的主体中创建的变量是全局变量,因此具有全局作用域。这个变量没有限制,可以在任何地方使用/访问。再次强调,通过查看示例来学习这是最好的方法:
def add_minor(person):
person.append('math')
def switch_majors(person):
person = ['physics'] # here, the person variable has a local scope, meaning its value/update only happens within the function, and is "ignored" outside of it
person.append('economics')
# all variables created out here have a global scope
John = ['computer_science']
Tim = John
add_minor(Tim)
switch_majors(John)
print(John, Tim)
示例
哪个代码片段不会修改变量?
A
a = [3, 4]
b = [6, 7]
def do_stuff(a, b):
return (a.append(5), b.append(8))
do_stuff(a, b)
B
a = 3
b = 5
def do_stuff(a, b):
a += 1
b += 2
do_stuff(a, b)
C
a = [3, 4]
b = [6, 7]
def do_stuff(a, b):
a += [5]
b += [8]
do_stuff(a, b)
答案
B
B 是正确答案,因为在 Python 中ints是不可变的。这意味着在函数内部将a增加 1 和将b增加 2 只会为 a 和 b 创建新的对象。这些新对象将限制在函数的作用域内,因此变量不会被修改。
然而,列表是可变对象,向其中添加值并不会创建新的对象。函数只是更新已经具有全局作用域的变量,因此这些变量被修改。
字典
字典是 Python 中重要且有用的结构。字典由键值对组成,其中值是通过键提取的。你将在本课程中大量使用字典,尤其是在后面的章节中。以下是一些使用字典的示例:
# definition of a dictionary myDict = {
"number": 357,
"major": "computer science",
"credit hours": 3
}
# dictionaries are mutable, thus can be modified, either modifying an existing value or creating a new key myDict["major"] = "math"
myDict["level"] = "undergrad"
# looping through the keys or the values over the dictionary for x in myDict:
print(x)
print(myDict[x])
for x in myDict.values():
print(x)
# there are multiple ways to remove an existing entry, here is one example myDict.pop("level")
# copy an existing dictionary into a new reference anotherDict = myDict.copy()
这里是官方文档关于字典和一些其他有用的数据结构。
类型注解
Python 是一种动态类型语言,这意味着变量的类型是在运行时确定的。正如你可能已经注意到的,这就是为什么我们有声明和初始化变量而不必为变量分配类型的奢侈。在 C++或 Java 这样的语言中,这是不允许的。
类型注解,然而,为开发者提供了一种指定变量、函数参数或函数结果类型的方法。虽然它并不真正提高性能,但它有助于开发者更好地理解他们正在处理的数据类型,无论是变量还是函数调用的输入和输出。以下是一个类型注解变量/函数定义的示例:
# simple variable declaration (the type we're used to) a = 5
# type annotated variable declaration a: int = 5
# simple function definition (the type we're used to) def add_two_numbers(a, b):
return a + b
# type annotated function definition (both inputs and output) def add_two_numbers(a: int, b: int) -> int:
return a + b
NumPy
NumPy 是一个用于数值计算的 Python 库。它几乎完全用 C 和 C++开发,性能极高,可以轻松支持大量数据的操作。本节将简要介绍一些你将在整个课程中使用的常见 NumPy 工具。虽然本节将解释一些这些常见工具,但NumPy 文档提供了更详细的说明,并且始终是当你不确定如何使用特定函数时的首选资源。
NumPy 数组
NumPy 数组通常比列表更受欢迎,因为你可以对它们进行高度性能的操作以完成任何任务。这在数值方法这样的课程中尤为重要。以下是你可以初始化不同类型 NumPy 数组的方法:
import numpy as np
# creates a 2d array of zeros (conceptually a matrix) that has shape 2 x 2 np.zeros((2, 2))
# creates a 2d array of ones (conceptually a matrix) that has shape 2 x 2 np.ones((2, 2))
# creates an array of numbers that are evenly spaced between 2 and 3 (4 numbers in this case) np.linspace(2, 3, 4)
# creates a 2d array of random numbers between 0 and 1 that has shape 2 x 2 np.random.rand(2, 2)
# creates an empty 2d array (conceptually a matrix) that has shape 2 x 2 np.empty((2, 2))
我们可以使用以下函数找到有关 NumPy 数组的更多信息,并对其进行更多操作:
import numpy as np
a = np.zeros((2, 2))
# we can get the shape of our NumPy array with the following function print(a.shape) # will return (2, 2)
# this will give us the data type of the array elements print(a.dtype) # returns float
# If we want to convert each element in the array to an int instead of float, we can perform the following operation: a = a.astype(int)
print(a.dtype) # returns int
# this creates a deep copy of the array, so changing one won't affect the other b = a.copy()
索引和切片
我们可以使用 NumPy 数组上的索引和切片来提取数组/矩阵中的特定信息。这将成为课程的一个固定部分,所以现在就习惯使用索引/切片会更好!注意,本节与上面的索引部分类似。NumPy 数组 a 将遵循以下标准:a[i:j:k],其中i是迭代的起始索引,j是迭代的停止索引(不包括),k是步长。
import numpy as np
a = np.array([3, 7, 9, 10, 3, 5])
b = np.array([[1, 2, 3], [4, 5, 6]])
# basic indexing for both 1d and 2d NumPy arrays (for 2d arrays we specify both the row and col) print(a[2]) # prints 9 print(b[0, 0]) # prints 1
# slicing examples for both 1d and 2d NumPy arrays (for 2d arrays we specify both the row and col) print(a[1:3]) # prints [7, 9] print(b[0:1, 2]) # prints [3]
# If we leave the row/col index empty or use a colon(:) then we're saying that we select the entire row/col print(b[:1]) # this assumes the starting index of the row is 0, so we select the entire first row, prints [[1, 2, 3]]
数组操作
数组操作在后续章节中某些公式需要构建矩阵或对矩阵执行某些操作(例如,转置矩阵)时特别有用。以下是一些示例:
import numpy as np
a = np.array([3, 7, 9, 10, 3, 5])
b = np.array([[1, 2, 3], [4, 5, 6]])
# we can reshape an array as long as the new shape has the same number of elements as the original shape b = np.reshape(b, (6, 1))
a = np.reshape(a, (3, 2))
# we can flatten an array so that all the elements are collapsed into one dimension a = a.flatten()
# we can get the transpose of a NumPy array via the following command a_transpose = a.T
数组数学
NumPy 提供了一些可以在数组中的每个元素上执行数学函数。而不是遍历每个元素,这些函数将在整个数组上执行操作,因此非常方便。在数值方法中哪些数学函数可能是相关的?让我们看看:
import numpy as np
a = np.array([[8, 9]])
b = np.array([[1, 2, 3], [4, 5, 6]])
# The most important operation you'll do is matrix multiplication, we can do this easily in 2 ways c = np.dot(a, b)
# or c = a @ b
# We can do a lot of other operations d = np.sin(a)
e = np.cos(a)
f = np.exp(a)
g = np.sum(a)
h = np.mean(a)
i = np.min(a)
线性代数
这个课程通常会要求你在向量/矩阵上执行线性代数操作。这就是numpy.linalg库和它提供的以下函数将非常有用的地方:
import numpy.linalg as la
# To take the matrix inverse of a matrix A: matrix_inv = la.inv(A)
# To get the eigenvalues/eigenvectors of a matrix A: eigval, eigvec = la.eig(A)
# To calculate the norm of a vector or a matrix A: vec_norm = la.norm(A) # can specify what type of norm as an additional param
# To solve linear equations for an equation Ax = b x = la.solve(A, b)
随机数
随机数总是数值方法的一个基本组成部分。NumPy 提供了几个函数,使得使用随机数变得非常简单,这在蒙特卡洛等章节中将是关键。让我们深入了解 NumPy 为随机数提供了什么:
import numpy as np
# Generating random numbers from 0 to 1: a = np.random.rand(3, 2) # creates a 3 x 2 array that is populated with random nums from 0 to 1
# Generating a random integer from 0 to 100: b = np.random.randint(100)
# Generate a random value based on an array of values: c = np.random.choice([1, 2, 3, 4]) # will randomly return one of the values within the array
Python 还有一个与 NumPy 分开的随机模块,但可以用来执行与上面介绍的操作非常相似的操作。
广播
广播是 Python 中的一个强大技术,它允许我们在形状不同的两个数组之间执行算术运算。
假设我们有一个较小的数组A(形状为 1 x 5)和一个较大的数组B(形状为 4 x 5),我们想要将这些数组相加。
没有广播,只有 B 的第一行会被 A 修改。然而,有了广播,A 的值会被添加到 B 的每一行。因此,A 被广播到 B 上。维度大小需要像这个例子中那样协作,否则在执行这个算术运算时我们会收到一些错误。
这里有一个示例来说明这个概念:
import numpy as np
A = np.array([[1, 2, 3, 4, 5]])
B = np.array([
[10, 20, 30, 40, 50],
[60, 70, 80, 90, 100],
[110, 120, 130, 140, 150],
[160, 170, 180, 190, 200]
])
# Add A to B using broadcasting C = B + A
# C = np.array([[ 11, 22, 33, 44, 55],
# [ 61, 72, 83, 94, 105],
# [111, 122, 133, 144, 155],
# [161, 172, 183, 194, 205]])
print(C)
这个结果展示了如何将数组 A 的值添加到数组 B 的每一行,这得益于广播。A 的维度(1 x 5)与 B(4 x 5)兼容,使得 A 能够“拉伸”到 B 上以执行逐元素加法。
外部链接
这里有一些我们将要在 CS 357 中使用其他包的文档。
更新日志
-
2024 年 3 月 17 日:Dev Singh(dsingh14)——修改了笔记内容以提高清晰度
-
2024 年 3 月 16 日:Arnav Aggarwal (arnava4) — 将笔记与幻灯片对齐并添加了额外的示例
查看剩余条目
作者
- CS 357 课程工作人员
误差和复杂性
查看幻灯片
如果您在这里看不到 PDF,请点击这里下载 PDF。
学习目标
-
比较和对比相对误差和绝对误差
-
将成本分类为 \(\mathcal{O}(n^p)\)
-
将误差分类为 \(\mathcal{O}(h^p)\)
-
识别代数增长和指数增长与收敛
整体情况
-
数值算法以其成本和误差以及它们之间的权衡而区分。
-
在可能的情况下,本课程中介绍的计算算法或方法会指出它们的误差和成本。这些可能是精确表达式或渐近界限,如 \(h \to 0\) 时的 \(\mathcal{O}(h²)\) 或 \(n \to \infty\) 时的 \(\mathcal{O}(n³)\)。对于渐近分析,我们总是指明极限。
科学记数法
使用科学记数法,一个数可以表示为
其中 \(r\) 是一个在 \(1 \leq r < 10\) 范围内的系数,\(m\) 是指数。
示例:让我们将这些数字转换为科学记数法:
绝对误差和相对误差
使用数值方法计算的结果是不准确的——它们是真实值的近似。我们可以将一个近似结果表示为真实值和一些误差的组合:
给定这个问题设置,我们可以定义绝对误差为:
这告诉我们我们的近似结果与实际答案有多接近。然而,绝对误差可能会因为 \(x\) 的大小而成为一个令人不满意且具有误导性的误差表示。
| 情况 1 | 情况 2 |
|---|---|
| \(x = 0.1\), \(\hat{x} = 0.2\) | \(x = 100.0\), \(\hat{x} = 100.1\) |
| \(\mid x - \hat{x} \mid = 0.1\) | \(\mid x - \hat{x} \mid = 0.1\) |
在这两种情况下,绝对误差相同,都是 0.1。然而,我们会直觉地认为情况 2 比情况 1 更准确,因为情况 1 中的近似值是真实值的两倍。因此,我们定义相对误差,这将是一个与大小无关的误差估计。为了获得这个值,我们只需将绝对误差除以真实值的绝对值。
如果我们再次考虑这两种情况,我们可以看到相对误差在第二种情况下会低得多,因为相对误差与大小无关。
| 情况 1 | 情况 2 |
|---|---|
| \(x = 0.1\), \(\hat{x} = 0.2\) | \(x = 100.0\), \(\hat{x} = 100.1\) |
| \(\frac{\mid x - \hat{x} \mid}{\mid x \mid} = 1\) | \(\frac{\mid x - \hat{x} \mid}{\mid x \mid} = 10^{-3}\) |
向量的绝对误差和相对误差
如果我们的计算量是向量,那么我们不用绝对值函数,而可以用范数。因此,我们的公式变为
我们取差分的范数(而不是范数的差),因为我们感兴趣的是这两个量有多远。这样,我们计算差分向量,然后使用向量范数来找到该差分向量的长度。
有效数字/数位
有效数字是一个数字,它携带有意义的信息。它们是从最左边的非零数字开始,以最右边的“正确”数字结束的数字,包括精确的末尾零。例如:
-
数字 3.14159 有六个有效数字。
-
数字 0.00035 有两个有效数字。
-
数字 0.000350 有三个有效数字。
近似值的有效数字
近似结果 \(\hat{x}\) 的 \(n\) 个有效数字对应于真实值 \(x\),如果绝对误差 \(\vert x - \hat{x}\vert\) 在从 \(x\) 最左边的非零(首位)数字开始计数的第一个 \(n\) 位小数中包含零,然后是 0 到 4 之间的一个数字。
示例: 假设 \(x = 3.141592653\),假设 \(\hat{x}\) 是近似结果:
换句话说,有效数字的数量告诉我们 \(x\) 和 \(\hat{x}\) 有多少位是相同的。
因此,我们可以观察到绝对误差被以下所限制:
为了找到相对误差的界限,让我们定义 \(x\) 和 \(\hat{x}\) 如下:
绝对误差可以这样表述:
由于科学记数法,我们知道 \(1 \leq q < 10\),所以:
通常,我们将使用经验法则来计算相对误差的上界:如果一个近似值有 \(n\) 个准确的有效数字,那么相对误差是
截断误差与舍入误差
舍入误差是在计算中对值进行舍入时产生的误差。由于计算机使用有限精度并且对存储一个数值值的内存有限制,因此这种情况会不断发生。用有限小数展开来近似 \(\frac{1}{3} = 0.33333\dots\) 是舍入误差的一个例子。
截断误差是在使用近似算法代替精确的数学过程或函数时产生的误差。例如,在评估函数的情况下,我们可能用有限泰勒级数表示我们的函数,直到 \(n\) 次方。截断误差是由于没有使用 \(n+1\) 次方及以上的项而产生的误差。
大 O 表示法
大 O 表示法用于理解和描述渐近行为。在趋近于 0 或\(\infty\)的情况下的定义如下:
设 \(f\) 和 \(g\) 是两个函数。那么当 \(x \rightarrow \infty\) 时,\(f(x) = \mathcal{O}(g(x))\) 当且仅当存在一个值 \(M\) 和某个 \(x_0\),使得 \(|f(x)| \leq M|g(x)|\) 对于所有 \(x\) 成立,其中 \(x\geq x_0\)
设 \(f\) 和 \(g\) 是两个函数。那么当 \(h \rightarrow 0\) 时,\(f(h) = \mathcal{O}(g(h))\) 当且仅当存在一个值 \(M\) 和某个 \(h_0\),使得 \(|f(h)| \leq M|g(h)|\) 对于所有 \(h\) 成立,其中 \(0 < h < h_0\)
但如果我们想考虑函数趋近于任意值的情况呢?那么我们可以重新定义表达式如下:
设 \(f\) 和 \(g\) 是两个函数。那么当 \(x \rightarrow a\) 时,\(f(x) = \mathcal{O}(g(x))\) 当且仅当存在一个值 \(M\) 和某个 \(\delta\),使得 \(|f(x)| \leq M|g(x)|\) 对于所有 \(x\) 成立,其中 \(0 < |x − a| < \delta\)
大 O 分析
由于大 O 表示法用于理解渐近行为,我们感兴趣的是增长最快的项,这些项定义了函数的极限行为。
例如,考虑函数 \(f(x) = 2x² + 27x + 1000\)
当 \(x \rightarrow \infty\) 时,项 \(x²\) 是增长最快的,因此它是最重要的,所以 \(f(x) = O(x²)\)。
最快增长到最慢增长常见项的层次结构,其中 \(c\) 是一个常数:
大 O 表示法示例 - 时间复杂度
我们可以使用大 O 来描述我们算法的时间复杂度。
考虑矩阵-矩阵乘法的情况。如果我们的每个矩阵的大小是 \(n \times n\),为了乘法矩阵,我们必须在每个元素上计算内积,这需要 \(n\) 次乘法和 \(n\) 次求和。在一个 \(n \times n\) 的矩阵中,有 \(n²\) 个元素,这意味着有 \(n² (2n) = 2n³\) 次操作,所以乘法矩阵所需的时间与 \(2n³\) 成正比。
然而,在尝试理解时间复杂度时,我们关注的是算法基于输入大小的渐近增长率,因此我们可以这样说,乘矩阵所需的时间是 \(\mathcal{O}(n³)\),这意味着 \(\text{运行时间} \approx C \cdot n³\)。
假设我们知道对于 \(n_1=1000\),矩阵-矩阵乘法需要 5 秒。估计如果我们把矩阵的大小加倍到 \(2n \times 2n\),需要多少时间。
我们知道:
因此,当我们把矩阵的大小加倍到 \(2n \times 2n\) 时,时间变为 \((2n)³ = 8n³\)。因此,运行时间将大约是原来的 8 倍。
大 O 记号示例 - 截断误差
我们也可以使用大 O 记号来描述截断误差。一个数值方法被称为 \(n\) 阶精确,如果其截断误差 \(E(h)\) 符合 \(E(h) = \mathcal{O}(h^n)\)。
示例 1
正弦函数可以表示为一个无穷级数:
假设我们取一个近似值:
我们可以将截断误差定义为:
相反,使用大 O 记号,我们定义截断误差为:
示例 2
考虑解决一个插值问题。我们有一个长度为 \(h\) 的区间,其中我们的插值函数是有效的,并且我们知道我们的近似是 \(\mathcal{O}(h²)\) 阶。这意味着,当我们减小 \(h\)(区间长度)时,我们的误差将呈二次方减少。使用大 O 的定义,我们知道 \(\text{误差} = C \cdot h²\),其中 \(C\) 是某个常数。
在某些情况下,我们可能不知道 \(E(h) = \mathcal{O}(h^n)\) 中的指数。我们可以通过计算 \(h\) 的两个不同值处的误差来估计它。假设我们有两个量,\(h_1 = 0.5\) 和 \(h_2 = 0.25\)。我们计算相应的误差为 \(E(h_1) = 0.125\) 和 \(E(h_2) = 0.015625\)。然后,由于 \(E(h) = \mathcal{O}(h^n)\),我们有:
解这个方程得到 \(n = 3\)。
大 O 记号示例 - 常数的作用
在大 O 记号定义中,对常数 \(M\) 的过分重视是不重要的;它本质上是不确定的。
假设 \(f_1(n) = 10^{-20}n²\) 和 \(f_2(n) = 10^{20}n²\)。虽然对于所有 \(n\) 的值,\(f_2\) 都比 \(f_1\) 大得多,但是它们都是 \(\mathcal{O}(n²)\);如果我们选择任何 \(M_1 \geq 10^{-20}\) 和 \(M_2 \geq 10^{20}\) 的常数,这是显而易见的。
然而,对于任何 \(M \geq 10^{40}\) 的常数,\(f_2(n) = \mathcal{O}(10^{-20}n²)\) 也是正确的。
因此,在 \(\mathcal{O}\) 内包含一个常数基本上是没有意义的。
问题: 给出 \(f_2(n) = \mathcal{O}(g(n))\) 的最紧界函数 \(g(n)\) 是什么?
解答:答案是 \(g(n) = n²\)。对于任何 \(r < 2\),不存在常数 \(M\) 使得对于所有足够大的 \(n\),\(|f_2(n)| \leq Mn^r\)。因此,对于 \(r < 2\),\(n^r\) 不是 \(f_2\) 的上界。对于任何 \(q > 2\),存在一对常数 \(M_1\) 和 \(M_2\),使得对于所有足够大的 \(n\):
然而,我们不能找到一对常数 \(M_3\) 和 \(M_4\),使得:
因此,我们无法在 \(f_2(n)\) 和 \(n²\) 之间“拟合”另一个函数,所以 \(n²\) 是最紧的上界。
人们可能会想,正确的答案实际上应该是 \(g(n) = 10^{20}n²\);然而,这实际上并没有提供关于 \(f_2\) 增长的任何额外信息。注意,我们没有在上面的不等式中指定 \(M_1\) 和 \(M_2\) 是什么。大 \(O\) 符号说什么关于常数的规模。以下陈述
都等价,因为它们都提供了关于 \(f_2\) 增长的相同信息,因为常数没有指定。由于 \(10^{-20}\) 非常小,可能会诱使人们得出结论,它比其他两个更“紧”,但这并不正确。因此,始终最好避免在 \(\mathcal{O}\) 内放置不必要的常数,并且我们期望你在本课程中避免这样做。
收敛定义
代数增长/收敛是指我们感兴趣的序列中的系数 \(a_n\) 在增长时表现为 \(\mathcal{O}(n^{\alpha})\),在收敛时表现为 \(\mathcal{O}(1/n^{\alpha})\),其中 \(\alpha\) 被称为收敛的代数指数。一个代数增长或收敛的序列在双对数图中是一条直线。
指数增长/收敛是指我们感兴趣的序列的系数 \(a_n\) 在增长时表现为 \(\mathcal{O}(e^{qn^{\beta}})\),在收敛时表现为 \(\mathcal{O}(e^{-qn^{\beta}})\),其中 \(q\) 是某个 \(\beta > 0\) 的常数。指数增长比代数增长快得多。指数增长/收敛有时也称为谱增长/收敛。在双对数图中,指数增长的序列是一条直线。指数收敛通常进一步分为超几何收敛、几何收敛或亚几何收敛。



来自 J. P. Boyd 的资料,Chebyshev 和 Fourier 波谱方法,第 2 版,Dover,纽约,2001 年。
复习问题
-
相对误差的公式是什么?
-
绝对误差的公式是什么?
-
通常哪种方法计算误差更好?
-
如果你有一个 \(k\) 个有效数字是准确的,你的相对误差的最紧界限是什么?
-
给定一个最大相对误差,你能有的最大(或最小)值是多少?
-
你如何计算向量的相对误差和绝对误差?
-
什么是截断误差?
-
什么是舍入误差?
-
一个算法需要 \(O(n³)\) 的时间意味着什么?
-
你能给出一个操作需要 \(O(n²)\) 时间的例子吗?
-
误差遵循 \(O(h⁴)\) 意味着什么?
-
你能简化 \(O(h⁵ + h² + h)\) 吗?你需要做出什么假设?
-
如果你已知一个操作是 \(O(n⁴)\),你能根据已有的输入预测其在未见过的输入上的时间/误差吗?
-
如果你被给出了一个操作的运行时间或误差数据,你能找到最佳的 \(x\) 使得该操作是 \(O(n^x)\) 吗?
-
什么是代数增长/收敛?
-
什么是指数增长/收敛?
其他资源的链接
变更日志
-
2024 年 3 月 30 日:Kriti Chandak (kritic3) — 添加幻灯片信息并添加示例
-
2022 年 1 月 27 日:Victor Zhao (chenyan4) — 修正准确有效数字的术语,修正经验不等式规则
-
2022 年 1 月 20 日:Victor Zhao (chenyan4) — 更改真实值的表示法
查看剩余条目
+ 2020 年 4 月 25 日:Mariana Silva (mfsilva) — 小幅度文本修订
+ 2020 年 2 月 19 日:Peter Sentz (sentz2) — 添加关于常数的角色章节,将大 O 符号改为 "mathcal"
+ 2020 年 1 月 26 日:Wanjun Jiang (wjiang24) — 添加科学记数法、数字和图表
+ 2018 年 1 月 31 日:Aming Ni (amingni2) — 更改了三个图表
+ 2018 年 1 月 16 日:Yu Meng (yumeng5) — 全文小幅度修正
+ 2017 年 11 月 2 日:Erin Carrier (ecarrie2) — 添加变更日志
+ 2017 年 10 月 26 日:Erin Carrier (ecarrie2) — 添加复习问题,全文小幅度修改以更好地匹配课堂笔记中的术语
+ 2017 年 10 月 23 日:约翰·多赫蒂(jjdoher2)——首次完整草案
+ 2017 年 10 月 17 日:卢克·奥利森(lukeo)——大纲
作者
- CS 357 课程工作人员
浮点表示
查看幻灯片
如果在这里看不到 PDF,请点击这里下载 PDF。
学习目标
-
在浮点数系中表示数字
-
评估不同表示的范围、精度和准确性
-
定义机器精度
-
识别可表示的最小和最大浮点数
-
处理特殊情况和非正常数值
数制与基数
存在着多种数制,可以用来表示一个数。在常见的基数 10(十进制)系统中,每个数字可以取 0 到 9 之间的 10 个值。在基数 2(二进制)中,每个数字可以取 0 或 1 之间的 2 个值。
对于给定的\(\beta\),在\(\beta\)进制中,我们有:
一些常用的编号系统基数包括:
-
十进制:\(\beta=10\)
-
二进制:\(\beta=2\)
-
八进制:\(\beta=8\)
-
十六进制 \(\beta=16\)
示例:
十进制基数:\((426.97)_{10}\)
答案
\(\begin{equation}(426.97)_{10} = 4 \times 10² + 2 \times 10¹ + 6 \times 10⁰ + 9 \times 10^{-1} + 7 \times 10^{-2} \end{equation}\)
二进制基数:\((1011.001)_{2}\)
答案
\((1011.001)_{2} = 1 \times 2³ + 0 \times 2² + 1 \times 2¹ + 1 \times 2⁰ + 0 \times 2^{-1} + 0 \times 2^{-2} + 1 \times 2^{-3} = (11.125)_{10}\)
在十进制和二进制之间转换整数
现代计算机使用晶体管来存储数据。这些晶体管可以是开启状态(1)或关闭状态(0)。为了在计算机中存储整数,我们必须首先将它们转换为二进制。例如,23 的二进制表示为\((10111)_2\)。
将整数从二进制表示(基数 2)转换为十进制表示(基数 10)是很容易的。只需将每个数字乘以 2 的递增幂,如下所示:
将整数从十进制转换为二进制是一个类似的过程,除了不是乘以 2,而是除以 2 并记录余数:
因此,\((23)_{10}\)在二进制中表示为\((10111)_2\)。
您可能发现以下额外资源对复习有帮助:十进制转二进制 1 和 十进制转二进制 2
在十进制和二进制之间转换分数
实数增加了额外的复杂性。它们不仅有一个前导整数,还有一个小数部分。现在,我们将十进制数 23.375 表示为 \((10111.011)_2\)。当然,实际的机器表示取决于我们使用的是定点表示还是浮点表示,但这一点将在后面的章节中讨论。
将具有小数部分的数字从二进制转换为十进制与转换为整数类似,不同之处在于我们继续对分数部分使用 2 的负幂:
将十进制小数转换为二进制,首先将整数部分转换为二进制,如前所述。然后,取小数部分(忽略整数部分)并将其乘以 2。得到的整数部分将是二进制位。丢弃整数部分,并继续乘以 2 的过程,直到小数部分变为 0。例如:
通过组合整数部分和小数部分,我们发现 \(23.375 = (10111.011)_2\)。
并非所有分数都可以使用有限位数的二进制表示。例如,如果您尝试使用上述技术对 0.1 这样的数字进行处理,您会发现剩余的分数开始重复:
如您所见,十进制数 0.1 在二进制中表示为无限重复的小数序列 \((0.00011001100110011…)_2\)。浮点数中存储的确切位数取决于我们使用的是单精度还是双精度。
(无符号)定点表示
在定点表示中,数字使用固定数量的位来存储整数部分,以及固定数量的位来存储小数部分。
假设我们用 64 位来存储一个实数,其中 32 位存储整数部分,32 位存储小数部分。
最小数字
当 \(a_i\) 和 \(b_i\) 的所有值都是 \(0\) 时,我们得到可表示的最小数字,除了 \(b_{32}\)。
最大数字
当 \(a_i\) 和 \(b_i\) 的所有值都是 \(1\) 时,我们得到可表示的最大数字。
二进制小数点位置
我们在评估表示时考虑范围和精度。
范围: 可能的最大数和最小数之间的差值。
精度: 任意两个数之间可能的最小差值。
考虑一个 8 位系统,其中 6 位存储整数部分,2 位存储小数部分。它的范围和精度是多少?
答案
最小的数
\(000000.01 = 0.25\)
\(000000.10 = 0.5\)
最大的数
\(111111.10 = 63.5\)
\(111111.11 = 63.75\)
范围
\(63.75 - 0.25 = 63.5\)
精度
\(0.5 - 0.25 = 63.75 - 63.5 = 0.25\)
对于一个 8 位系统,其中 2 位存储整数部分,6 位存储小数部分,情况如何?
答案
最小的数
\(00.000001 = 0.015625\)
\(00.000010 = 0.03125\)
最大的数
\(11.111110 = 3.96875\)
\(11.111111 = 3.984375\)
范围
\(3.984375 - 0.015625 = 3.96875\)
精度
\(0.03125 - 0.015625 = 3.984375 - 3.96875 = 0.015625\)
我们可以看到,增加整数位会增加范围,而增加小数位会增加精度。很难决定你需要多少精度和范围。
修正:让二进制小数点“浮动”
浮点数
二进制数的浮点表示类似于十进制的科学记数法。类似于你可以将 23.375 表示为
你可以将 \((10111.011)_2\) 表示为
浮点数可以用相同的固定位数表示不同数量级的数(非常大和非常小)。
更正式地说,我们可以将一个浮点数 \(x\) 定义为
其中:
-
\(\pm\) 是符号
-
\(q\) 是尾数
-
\(m\) 是指数
除了零和下溢数(下面讨论)的特殊情况外,尾数总是以归一化形式存在
其中:
- \(f\) 是尾数的小数部分
每次我们存储一个归一化浮点数时,都假设 1 存在。我们不存储整个尾数,只存储小数部分。这被称为“隐藏位表示”,它提供了额外的精度位。
归一化浮点数系统的性质
在归一化的二进制浮点数系统中,一个数 \(x\) 的形式为
-
数字: \(b_i \in {0, 1}\)
-
指数范围: 整数 \(m \in [L,U]\)
-
精度: \(p = n + 1\)
-
最小的正归一化浮点数: $ 2^L$
-
最大的正归一化浮点数: $ 2{U+1}(1-2)$
示例
- 任何大于 -28.0 且小于 +28.0 的数都会溢出到无穷大。
任何比 0.0625 更接近零的数都会下溢到零。
- 最大的规范化正数:
答案
-
整数范围
-
在这种表示法中,可以精确表示的整数范围是多少?
机器精度
或者对于一般的规范化浮点系统 \(1.f \times 2^m\),其中 \(f\) 用 \(n\) 位表示,机器精度定义为:
在编程语言中,这些值通常作为预定义的常量可用。例如,在 C 语言中,这些常量是 FLT_EPSILON 和 DBL_EPSILON,并在 float.h 库中定义。在 Python 中,您可以使用以下代码片段访问这些值。
最小的规范化正数:
import numpy as np
# Single Precision eps_single = np.finfo(np.float32).eps
print("Single precision machine eps = {}".format(eps_single))
# Double Precision eps_double = np.finfo(np.float64).eps
print("Double precision machine eps = {}".format(eps_double))
注意: 在各种资源中,机器精度的定义有很多,例如,最小的数,使得 \(\text{fl}(1 + \epsilon_m) \ne 1\)。这些其他定义可能根据舍入模式(下一个主题)的不同而给出与上述定义略有不同的值。在本课程中,我们将始终使用上述“间隙”定义中的值。
$$\pm 1.b_1b_2 \times 2^m\ for \ m \in [-4,4]\ and\ b_i \in {0, 1}$$ $$(1.00)_2 \times 2⁰ = 1 \hspace{1.8cm} (1.01)_2 \times 2⁰ = 1.25$$ $$\epsilon_m = (0.01)_2 \times 2⁰ = 0.25$$
我们可以看到,在这个浮点系统中,我们可以表示从 \((1)_{10}\) 到 \((8)_{10}\) 的每一个整数。然而,为了表示 \((9)_{10}\) 或 \((1001)_{2}\),我们需要在分数部分中超过两个位。这种精度限制导致整数范围以上的整数出现跳跃。
机器精度 (\(\epsilon_m\)) 被定义为 1 和下一个最大的浮点数之间的距离(间隙)。注意这个范围的上线假设为 \(1.00 \times 2³\) 的形式,其中 3 代表浮点系统的精度。因此,这个上限由 \(2^p\) 给出。
IEEE-754 单精度
^(图片来源:Fresheneesz 在英语维基百科项目.)
-
\(x = (-1)^s 1.f \times 2^m\)
-
1-bit 符号,s = 0:正号,s = 1:负号
-
8-bit 指数 \(c\),其中 \(c = m + 127\),我们需要为特殊情况保留指数数 $ c = (11111111)_2 = 255, c = (00000000)_2 = 0$,因此 \(0 < c < 255\)
-
23-bit 小数部分 \(f\)
-
计算机 epsilon:
-
对于 IEEE-754 单精度,\(\epsilon_m = 2^{-23}\),如下所示:
\[\epsilon_m = 1.\underbrace{000000...000}_{\text{22 bits}}{\bf 1} - 1.\underbrace{000000...000}_{\text{22 bits}}{\bf 0} = 2^{-23} \]
-
-
最小的正规范化浮点数:\(UFL = 2^L = 2^{-126} \approx 1.2 \times 10^{-38}\)
-
最大的正规范化浮点数:\(OFL = 2^{U+1}(1 - 2^{-p}) = 2^{128}(1 - 2^{-24}) \approx 3.4 \times 10^{38}\)
指数被移位 127 以避免存储负号。我们不是存储 \(m\),而是存储 \(c = m + 127\)。因此,可能的最大指数是 127,可能的最小指数是-126。
示例:
将二进制数 \((100101.101)_2\) 转换为规范化浮点数表示
答案
\((100101.101)_2 = (1.00101101)_2 \times 2⁵\) \(s = 0,\quad f = 00101101…00,\quad m = 5\) \(c=m + 127 = 132 = (10000100)_2\)
规范化浮点数表示:\(0 \; 10000100 \; 00101101000000000000000\)
关于 IEEE 浮点数 的更多信息
IEEE-754 双精度
^(图片来源:Codekaizen.)
-
\(x = (-1)^s 1.f \times 2^m\)
-
1-bit 符号,s = 0:正号,s = 1:负号
-
11-bit 指数 \(c\),其中 $ c = m + 1023$,我们需要为特殊情况保留指数数 $ c = (11111111111)_2 = 2047, c = (00000000000)_2 = 0$,因此 \(0 < c < 2047\)
-
52-bit 小数部分 \(f\)
-
计算机 epsilon:
- 对于 IEEE-754 双精度,\(\epsilon_m = 2^{-52}\),如下所示:$$\epsilon_m = 1.\underbrace{000000...000}{\text{51 bits}}{\bf 1} - 1.\underbrace{000000...000}{\text{51 bits}}{\bf 0} = 2^{-52}$$
-
最小的正规范化浮点数:\(UFL = 2^L = 2^{-1022} \approx 2.2 \times 10^{-308}\)
-
最大的正规范化浮点数:\(OFL = 2^{U+1}(1 - 2^{-p}) = 2^{1024}(1 - 2^{-53}) \approx 1.8 \times 10^{308}\)
指数被移位 1023 以避免存储负号。我们不是存储 \(m\),而是存储 \(c = m + 1023\)。因此,可能的最大指数是 1023,可能的最小指数是-1022。
IEEE-754 中的特殊情况
在浮点数表示中会出现几个边缘情况。
零
在我们上面关于浮点数的定义中,我们说总是假设有一个前导 1。这对于大多数浮点数来说是正确的。一个值得注意的例外是零。为了将零存储为浮点数,我们存储指数位和分数位全为 0。请注意,根据符号位,可以有+0 和-0。
无穷大
如果浮点计算的结果超出了浮点数可能表示的范围,则该数被认为是无穷大。我们使用指数位全为 1 和分数位全为 0 来存储无穷大。\(+\infty\) 和 \(-\infty\) 通过符号位来区分。
NaN
导致非数值结果的操作在浮点数中以指数位全为 1 和非零分数位表示。
浮点数数轴
^(图片来源:计算中的不可避免错误。)
上图显示了 IEEE-754 浮点数系统的数轴。
子规格化数
如上所述,一个正常数被定义为尾数以 1 开头的浮点数,双精度中最小的正常数是 \(1.000… \times 2^{-1022}\)。可以表示的最小正常数被称为下溢水平,或UFL。
然而,我们可以通过移除尾数必须以 1 开头的限制来进一步减小数值。这些数被称为子规格化数,并且以指数位全为 0 来存储。技术上,零也是一个子规格化数。
重要的是要注意,子规格化数没有正常数那么多有效数字。
IEEE-754 单精度(32 位):
-
$ c = (00000000)_2 = 0 $
-
指数设置为 \(m\) = -126
-
最小的正子规格化浮点数:\(2^{-23} \times 2^{-126} \approx 1.4 \times 10^{-45}\)
IEEE-754 双精度(64 位):
-
$ c = (00000000000)_2 = 0 $
-
指数设置为 \(m\) = -1022
-
最小的正子规格化浮点数:\(2^{-52} \times 2^{-1022} \approx 4.9 \times 10^{-324}\)
使用非规格化数允许更渐进地向零下溢(然而,非规格化数没有规格化数那么多精确位)。
示例:
假设你被给定一个形式为(二进制)浮点数系统
其指数范围从 -2 到 5。
我们使用这个浮点数系统来表示以下子规格化数:
将这个子规格化数转换为十进制数。
答案
在这个浮点数系统中,子规格化数将表示为
我们将分数部分 \((11)_2\) 转换为十进制数,并使用指数范围的下限 \(L = -2\)。
复习问题
-
将十进制数转换为二进制。
-
将二进制数转换为十进制。
-
浮点数和固定点表示有什么区别?
-
给定一个实数,你将如何将其存储为机器数?
-
给定一个实数,将其存储为机器数时涉及到的舍入误差是什么?相对误差是什么?
-
解释浮点数的不同部分:符号、尾数和指数。
-
机器数的指数实际上是如何存储的?
-
什么是机器精度?
-
什么是下溢(UFL)?
-
什么是溢出?
-
为什么下溢有时不是问题?
-
给定一个玩具浮点系统,确定该系统的机器精度和 UFL。
-
如何将零存储为机器数?
-
什么是亚正常数?
-
机器中如何表示亚正常数?
-
为什么亚正常数有时有帮助?
-
使用亚正常数有哪些缺点?
更新日志
-
2025 年 9 月 1 日:Dev Singh (dsingh14) — 添加图片来源
-
2024 年 4 月 23 日:Apramey Hosahalli (apramey2) — 添加亚正常数示例
-
2024 年 4 月 22 日:Apramey Hosahalli (apramey2) — 修复格式并改进流程
查看剩余条目
+ 2024 年 4 月 2 日:Apramey Hosahalli (apramey2) — 添加整数范围章节和固定机器精度
+ 2024 年 4 月 2 日:Apramey Hosahalli (apramey2) — 调整示例,重新排序章节以匹配幻灯片
+ 2024 年 3 月 31 日:Apramey Hosahalli (apramey2) — 添加二进制小数点位置章节
+ 2024 年 3 月 27 日:Apramey Hosahalli (apramey2) — 更新学习目标并添加固定点表示章节
+ 2020 年 4 月 28 日:Mariana Silva (mfsilva) — 将舍入内容移至单独页面
+ 2020 年 1 月 26 日:Wanjun Jiang (wjiang24) — 添加规范化浮点数和示例
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 删除演示链接
+ 2017 年 12 月 13 日:Adam Stewart (adamjs5) — 修复数字系统和基数下的错误公式
+ 2017 年 12 月 8 日:Erin Carrier (ecarrie2) — 指定 UFL 为正数
+ 2017 年 11 月 19 日:Matthew West (mwest) — 添加机器精度图
+ 2017 年 11 月 18 日:Erin Carrier (ecarrie2) — 更新机器精度定义
+ 2017 年 11 月 15 日:Erin Carrier (ecarrie2) — 修复整数转换中的错误
+ 2017 年 11 月 14 日:Erin Carrier (ecarrie2) — 澄清何时存储规范化
+ 2017 年 11 月 13 日:Erin Carrier (ecarrie2) — 更新机器精度
+ 2017 年 11 月 13 日:Erin Carrier (ecarrie2) — 更新机器精度定义,修复不一致的大小写
+ 2017 年 11 月 12 日:Erin Carrier (ecarrie2) — 全文小修,添加更新日志,添加不同基数的数制章节
+ 2017 年 11 月 1 日:Adam Stewart (adamjs5) — 第一份完整草案
+ 2017 年 10 月 16 日:Luke Olson (lukeo) — 概述
作者
- CS 357 课程工作人员
取整
学习目标
-
使用 IEEE-754 浮点数标准理解不可表示数字的取整选项。
-
使用 IEEE-754 浮点数标准测量取整数字的误差
-
理解浮点数算术中的灾难性消去
-
预测浮点数算术中精度损失的结果
-
在一组数学上等价的公式中选择最优的,以最小化浮点误差
IEEE-754 中的取整选项
并非所有实数都可以精确地存储为浮点数。考虑一个规范化浮点数形式的实数:
其中 \(n\) 是尾数的位数,\(m\) 是给定浮点数系统的指数。如果 \(x\) 不能精确地表示为浮点数,它将表示为 \(x_{-}\) 或 \(x_{+}\),即最近的两个浮点数。
为了不失一般性,我们假设 \(x\) 是一个正数。在这种情况下,我们有:
以及
注意到连续浮点数之间的间隔并不均匀:当数字本身的幅度较小时,间隔较小;当数字变大时,间隔变大。例如,考虑简单的精度:
因此,使用机器精度来界定表示实数作为机器数时的误差会更好。
绝对误差:
相对误差:
使用这个不等式,观察 IEEE 单精度浮点数系统:\(\frac{ \vert fl(x) - x \vert }{ \vert x \vert } \le 2^{-23} \approx 1.2 \times 10^{-7}\)。由于该系统始终引入大约 \(10^{-7}\) 的相对误差,单精度浮点系统通常提供大约 7(十进制)位准确数字。
类似地,观察 IEEE 双精度浮点数系统:\(\frac{ \vert fl(x) - x \vert }{ \vert x \vert } \le 2^{-52} \approx 2.2 \times 10^{-16}\)。由于该系统始终引入大约 \(10^{-16}\) 的相对误差,双精度浮点系统通常提供大约 16(十进制)位准确数字。
示例:确定一个无法表示的数的舍入误差
如果我们四舍五入到最接近的,0.1 的双精度机器表示形式是什么?它引入了多少舍入误差?
答案
使用与之前章节中介绍将十进制分数转换为二进制的相同算法,我们构建以下表格:
| 前一个分数部分 $ \times 2 $ | 整数部分 | 当前分数部分 |
|---|---|---|
| 0.2 | 0 | 0.2 |
| 0.4 | 0 | 0.4 |
| 0.8 | 0 | 0.8 |
| 1.6 | 1 | 0.6 |
| 1.2 | 1 | 0.2 |
| 0.4 | 0 | 0.4 |
| 0.8 | 0 | 0.8 |
| 1.6 | 1 | 0.6 |
| 1.2 | 1 | 0.2 |
| ... | ... | ... |
我们可以观察到整数部分序列 $ {0, 0, 1, 1} $ 是循环出现的。
然后,我们有 $ 0.1 = (0.000110011\hspace{1mm}\overline{0011})_2 = (1.10011\hspace{1mm}\overline{0011})_2 \times 2^{-4}$ .
使用最近邻舍入,0.1 的双精度机器表示形式为元组 $ (s, c, f) $,其中 \(s\) 是符号位,\(c\) 是指数字段,\(f\) 是尾数:
$ s = 0 $
$ m = -4 \Rightarrow c = m + 1023 = 1019 = 01111111011$
$ f = 10011...0011...0011010 $
换句话说,0.1 的双精度机器表示是:
$ \bf{0\hspace{2mm}01111111011\hspace{2mm}\underbrace{10011...0011...0011010}_{52\text{ bits}}} $
然后,舍入误差是:
$ fl(0.1) - 0.1 = (0.00011001100110011...11010)_2 - (0.00011001100110011...1100110011\overline{0011})_2$ \(= (0.\underbrace{0...0}_{54\text{ 0's}}000110011\overline{0011})_2 = 2^{-54} \times 0.1 = 2^{-2} \times 0.1 \times 2^{-52} = \bf{0.025\epsilon_m}\)
示例:浮点数相等
假设你正在使用 IEEE 单精度数。找到满足 \(2⁸ + a \neq 2⁸\) 的最小可表示数 \(a\)。
答案
在本课程中,为了近似最小的数 \(x\),使得 \(2^n + x \neq 2^n\),我们使用公式 \(x = \epsilon_m \cdot 2^n\).
因此,鉴于 IEEE 单精度中的 \(\epsilon_m\) 为 \(2^{-23}\),答案是 \(\bf{a = 2^{-23} \cdot 2⁸ = 2^{-15}}\).
如果你感兴趣的是 \(\textbf{精确}\) 的最小数,这里是有解决方案(你不需要了解这个内容,对于 CS 357 课程,请只使用上述公式完成所有作业):
注意我们使用默认的舍入模式 - 舍入到最近的表示值。如果结果位于两个可表示值之间,则选择偶数表示值。"偶数"意味着最低位是零。
大于 \(2⁸\) 的最小可表示数是 \((2+\epsilon_m)\times 2⁸\).
设 \(x_{-} = 2⁸\) 和 \(x_{+} = (2+\epsilon_m)\times 2⁸\).
为了使 \(2⁸ + a\) 舍入到 \(x_{+}\),我们必须有 \(a \gt \frac{\vert x_{+} - x_{-} \vert}{2} = \frac{\epsilon_m\times 2⁸}{2} = \frac{2^{-23}\times 2⁸}{2} = 2^{-16}\).
大于 \(2^{-16}\) 的最小机器可表示数是 \((1 + \epsilon_m) \times 2^{-16}\).
因此 \(\bf{a = \bf{(1 + 2^{-23}) \times 2^{-16}}}\).
示例:任何 FPS 中浮点数的非均匀分布
考虑小浮点数系统 $x = \pm 1.b_1 b_2 \times 2^m $ 对于 \(m \in [-4, 4]\) 和 \(b_i \in \{0, 1\}\):
详细说明
$ (1.00)_2 \times 2^{-4} = 0.0625 $
$ (1.01)_2 \times 2^{-4} = 0.078125 $
$ (1.10)_2 \times 2^{-4} = 0.09375 $
$ (1.11)_2 \times 2^{-4} = 0.109375 $
$ (1.00)_2 \times 2^{-3} = 0.125 $
$ (1.01)_2 \times 2^{-3} = 0.15625 $
$ (1.10)_2 \times 2^{-3} = 0.1875 $
$ (1.11)_2 \times 2^{-3} = 0.21875 $
$ (1.00)_2 \times 2^{-2} = 0.25 $
$ (1.01)_2 \times 2^{-2} = 0.3125 $
$ (1.10)_2 \times 2^{-2} = 0.375 $
$ (1.11)_2 \times 2^{-2} = 0.4375 $
$ (1.00)_2 \times 2^{-1} = 0.5 $
$ (1.01)_2 \times 2^{-1} = 0.625 $
$ (1.10)_2 \times 2^{-1} = 0.75 $
$ (1.11)_2 \times 2^{-1} = 0.875 $
$ (1.00)_2 \times 2^{0} = 1.0 $
$ (1.01)_2 \times 2^{0} = 1.25 $
$ (1.10)_2 \times 2^{0} = 1.5 $
$ (1.11)_2 \times 2^{0} = 1.75 $
$ (1.00)_2 \times 2^{1} = 2.0 $
$ (1.01)_2 \times 2^{1} = 2.5 $
$ (1.10)_2 \times 2^{1} = 3.0 $
$ (1.11)_2 \times 2^{1} = 3.5 $
$ (1.00)_2 \times 2^{2} = 4.0 $
$ (1.01)_2 \times 2^{2} = 5.0 $
$ (1.10)_2 \times 2^{2} = 6.0 $
$ (1.11)_2 \times 2^{2} = 7.0 $
$ (1.00)_2 \times 2^{3} = 8.0 $
$ (1.01)_2 \times 2^{3} = 10.0 $
$ (1.10)_2 \times 2^{3} = 12.0 $
$ (1.11)_2 \times 2^{3} = 14.0 $
$ (1.00)_2 \times 2^{4} = 16.0 $
$ (1.01)_2 \times 2^{4} = 20.0 $
$ (1.10)_2 \times 2^{4} = 24.0 $
$ (1.11)_2 \times 2^{4} = 28.0 $
浮点运算的数学特性
- 不一定是结合律:\((x + y) + z \neq x + (y + z)\).
这是因为 \(fl(fl(x + y) + z) \neq fl(x + fl(y + z))\).
- 不一定是分配律:\(z \cdot (x + y) \neq z \cdot x + z \cdot y\).
这是因为 \(fl(z \cdot fl(x + y)) \neq fl(fl(z \cdot x) + fl(z \cdot y))\).
- 不一定是累积性:反复将一个非常小的数加到一个大数上可能没有任何效果。
示例:非结合特性
找到 \(a\)、\(b\) 和 \(c\),使得在双精度浮点算术中 \((a + b) + c \neq a + (b + c)\).
答案
设 \(a = \pi, b = 10^{100}, c = -10^{100}\)
在双精度浮点算术中:
\((a + b) + c = 10^{100} + (-10^{100}) = 0\)
\(a + (b + c) = \pi + 0 = \pi\)
示例:非分配特性
找到 \(a\)、\(b\) 和 \(c\),使得在双精度浮点算术中 \(c(a + b) \neq ca + cb\).
答案
设 \(a = 0.1, b = 0.2, c = 100\)
在双精度浮点算术中:
\(c(a + b) = 100 \times 0.30000000000000004 = 30.000000000000004\)
\(ca + cb = 10 + 20 = 30\)
浮点算术
浮点算术的基本思想是首先计算精确结果,然后将结果四舍五入以适应所需的精度:
浮点加法
添加两个浮点数很简单。基本思想是:
-
将两个数都转换为相同的指数
-
从系统中的前导位开始进行小学加法,直到你的系统中没有更多的数字
-
四舍五入结果
考虑一个数制,其中 \(x = \pm 1.b_1 b_2 b_3 \times 2^m\) 对于 \(m \in [-4, 4]\) 和 \(b_i \in \{0, 1\}\),我们从这个系统中进行两个数的加法运算。
示例 1:不需要舍入
设 \(a = (1.101)_2 \times 2¹\) 和 \(b = (1.001)_2 \times 2¹\),求 \(c = a + b\).
答案
\(c = a + b = (10.110)_2 \times 2¹ = (1.011)_2 \times 2²\)
示例 2:不需要舍入
设 \(a = (1.100)_2 \times 2¹\) 和 \(b = (1.100)_2 \times 2^{-1}\),求 \(c = a + b\).
答案
\(c = a + b = (1.100)_2 \times 2¹ + (0.011)_2 \times 2¹ = (1.111)_2 \times 2¹\)
示例 3:需要舍入且精度丢失
设 \(a = (1.a_1a_2a_3a_4a_5a_6...a_n...)_2 \times 2⁰\) 和 \(b = (1.b_1b_2b_3b_4b_5b_6...b_n...)_2 \times 2^{-8}\),求 \(c = a + b\)。假设使用单精度系统,且 \(n > 23\)。
答案
在单精度中:
\(a = (1.a_1a_2a_3a_4a_5a_6...a_{22}a_{23})_2 \times 2⁰\)
\(b = (1.b_1b_2b_3b_4b_5b_6...b_{22}b_{23})_2 \times 2^{-8}\)
因此 \(a + b = (1.a_1a_2a_3a_4a_5a_6...a_{22}a_{23})_2 \times 2⁰ + (0.00000001b_1b_2b_3b_4b_5b_6...b_{14}b_{15})_2 \times 2⁰\)
在这个例子中,结果 \(c = fl(a+b)\) 只包含来自 \(b\) 的 \(15\) 位精度,因此也会发生精度丢失。
示例 4:需要舍入且精度丢失
设 \(a = (1.101)_2 \times 2⁰\) 和 \(b = (1.000)_2 \times 2⁰\),求 \(c = a + b\)。如有必要,向下舍入。
答案
\(c = a + b = (10.101)_2 \times 2⁰ \approx (1.010)_2 \times 2¹\)
示例 5:需要舍入且精度丢失
设 \(a = (1.101)_2 \times 2¹\) 和 \(b = (1.001)_2 \times 2^{-1}\),求 \(c = a + b\)。如有必要,向下舍入。
答案
当我们对结果进行归一化时,我们得到 \(1.???? \times 2^{-3}\)。没有数据表明缺失的数字应该是什么。尽管浮点数将以小数点后 4 位存储,但它只能精确到单个有效数字。这种有效数字的丢失被称为 灾难性舍入。
更严格地,考虑一个一般情况,当 \(x \approx y\)。不失一般性,我们假设 \(x, y > 0\)(如果 \(x\) 和 \(y\) 是负数,那么 \(y - x = -(x - y) = -x - (-y)\),其中 \(-x\) 和 \(-y\) 都是正数并且大小相似)。假设我们已知以下条件来计算 \(fl(y - x)\):
可以证明,对于所有 \(n > 1\),精度损失会发生,并且当 \(n\) 增加时(换句话说,当 \(x\) 和 \(y\) 更相似时),它变得更加灾难性。然后,考虑当 \(n = 23\) 并且使用单精度浮点系统时,那么 \(fl(y - x) = 1.????... \times 2^{-23+m}\),其中小数点前的“1”成为唯一的显著性数字。注意,浮点系统可能会产生 \(fl(y - x) = 1.000... \times 2^{-n+m}\),但小数点后的所有数字都是“猜测”的,并且不是显著性数字。实际上,精度损失不是由于 \(fl(y-x)\) 而是由于从开始对 \(x, y\) 进行舍入以获得浮点系统可表示的数字。
示例:使用数学上等效的公式来防止舍入误差
考虑函数 \(f(x) = \sqrt{x^{2} + 1} - 1\). 当我们评估 \(f(x)\) 在 \(x\) 接近零的值时,可能会因为浮点数减法而遇到显著性损失。如果 \(x = 10^{-3}\),使用五位小数运算,\(f(10^{-3}) = \sqrt{10^{-6} + 1} - 1 = 0\)。我们如何找到一个替代公式来执行数学上等效的计算,而不发生灾难性的舍入误差?
答案
避免显著性数字损失的一种方法是消除减法:
$ f(x) = \sqrt{x^{2} + 1} - 1 = \frac{ (\sqrt{x^{2} + 1} - 1) \cdot (\sqrt{x^{2} + 1} + 1) } { \sqrt{x^{2} + 1} + 1 } = \frac{ x^{2} } { (\sqrt{x^{2} + 1} + 1) } $
因此,对于 \(x = 10^{-3}\),使用五位小数运算,$ f(10^{-3}) = \frac{ 10^{-6} } { 2 } $.
示例:当发生舍入时计算相对误差
如果 \(x = 0.3721448693\) 和 \(y = 0.3720214371\),在具有五位小数精度的计算机上计算 \((x − y)\) 的相对误差是多少?
答案
使用五位小数的精度,数字被四舍五入如下:
\(fl(x) = 0.37214\) 和 \(fl(y) = 0.37202\)
然后进行减法运算:
$fl(x) − fl(y) = 0.37214 − 0.37202 = 0.00012 $
操作的结果是:
\(fl(x − y) = 1.20000 × 10^{−2}\)
注意到最后四位数字被填充了虚假的零。
精确解和计算机解之间的相对误差由以下公式给出:
$\frac{\vert (x - y) - fl(x - y) \vert}{\vert (x - y) \vert} = \frac{0.0001234322 − 0.00012}{0.000123432} = \frac{0.0000034322}{0.000123432} \approx \bf{3 \times 10^{-2}} $
注意,与舍入的相对误差相比,减法引起的误差的幅度较大,其相对误差为:
$ \frac{\vert x - fl(x) \vert}{\vert x \vert} \approx 1.3 \times 10^{-5} $
复习问题
-
给定一个实数,将其存储为机器数时涉及到的舍入误差是什么?相对误差是多少?
-
我们如何界定将实数表示为归一化机器数时的相对误差?
-
什么是消去?为什么它是一个问题?
-
哪些类型的操作会导致灾难性消去?
-
给定两个用于评估相同值的方程,你能确定哪个在特定的 x 值上更准确,以及为什么吗?
更新日志
-
2024 年 3 月 31 日:Kaiyao Ke (kaiyaok2) — 将笔记与幻灯片对齐,添加了示例并重构了现有笔记
-
2022 年 1 月 30 日:Yuxuan Chen (yuxuan19) — 添加了新的 FP 内容;添加了 FP 减法示例
-
2020 年 4 月 28 日:Mariana Silva (mfsilva) — 从 FP 页面内容开始;添加了新的舍入文本
查看剩余条目
作者
- CS 357 课程工作人员
泰勒级数
学习目标
-
使用泰勒级数近似一个函数
-
使用泰勒级数近似函数导数
-
量化泰勒级数近似的误差
多项式概述
次数 \(n\) 的多项式
变量 \(x\) 的多项式总可以写成(或重新写成)以下形式
其中 \(a_{i}\) (\(0 \le i \le n\)) 是常数。
使用求和符号,我们可以简洁地表达多项式:
如果 \(a_n \neq 0\),则该多项式称为 \(n\) 次多项式。
次数 \(n\) 的多项式作为单项式的线性组合
变量 \(x\) 的单项式是 \(x\) 的幂,其中指数是非负整数(即 \(x^n\),其中 \(n\) 是非负整数)。你可能会看到单项式的另一种定义,它允许单项式中的系数为非零常数(即 \(a x^n\),其中 \(a\) 是非零且 \(n\) 是非负整数)。那么一个 \(n\) 次多项式
可以看作是单项式 \({x^i\ |\ 0 \le i \le n}\) 的线性组合。
泰勒级数展开
泰勒级数展开:无限
泰勒级数是一个函数的表示,它是一个无穷级数,这些项是通过在单一点上计算函数导数的值来计算的。关于 \(x=x_0\) 的函数 \(f(x)\) 的泰勒级数展开,如果 \(f(x)\) 在 \(x_0\) 处是可无限次微分的,那么它是一个幂级数
使用求和符号,我们可以简洁地表达泰勒级数:
(回忆一下 \(0! = 1\))
任何多项式的无限泰勒级数展开是该多项式本身。
泰勒级数展开:有限
然而,在实践中,我们通常无法计算函数的(无限)泰勒级数,或者函数在某些点处不可无限次微分。因此,我们通常必须截断泰勒级数(使用有限个项)来近似函数。
次数 \(n\) 的泰勒级数近似
如果我们使用泰勒级数的前 \(n+1\) 项,我们将得到
这被称为 \(n\) 次泰勒多项式。
任何多项式的 \(n\) 次有限泰勒级数展开是该多项式截断到 \(n\) 次的版本。
例子
泰勒级数展开的例子
我们将如何根据公式在点 \(x_0 = 0\) 处展开 \(f(x) = \cos x\)?
答案
好吧,我们需要计算 \(f(x)\) = cos \(x\) 在 \(x = x_0\) 处的导数。 $ \begin{align} f(x_0) &= \cos(0) = 1\ f'(x_0) &= -\sin(0) = 0\ f''(x_0) &= -\cos(0) = -1\ f'''(x_0) &= \sin(0) = 0\ f^{(4)}(x_0) &= \cos(0) = 1\ &\vdots \end{align} $ 然后 $ \begin{align} \cos x &= f(0)+\frac{f'(0)}{1!}x+\frac{f''(0)}{2!}x²+\frac{f'''(0)}{3!}x³+\dotsb\ &= 1 + 0 - \frac{1}{2}x² + 0 +\dotsb\ &= \sum_{k=0}^{\infty} \frac{(-1)k}{(2k)!}x \end{align} $
使用截断泰勒级数近似函数的例子
我们将如何使用关于点 \(x_0 = 0\) 的四阶泰勒多项式来近似 \(f(x) = \sin x\) 在 \(x = 2\) 处的值,按照以下公式
答案
好吧,我们需要计算 \(f(x)\) = sin \(x\) 在 \(x = x_0\) 处的前 4 阶导数。$$\begin{align} f(x_0) &= \sin(0) = 0\ f'(x_0) &= \cos(0) = 1\ f''(x_0) &= -\sin(0) = 0\ f'''(x_0) &= -\cos(0) = -1\ f^{(4)}(x_0) &= \sin(0) = 0 \end{align}$$然后$$\begin{align} \sin x &\approx f(0)+\frac{f'(0)}{1!}x+\frac{f''(0)}{2!}x²+\frac{f'''(0)}{3!}x³+\frac{f^{(4)}(0)}{4!}x⁴\ &= 0 + x + 0 - \frac{1}{3!}x³ + 0 \ &= x - \frac{1}{6}x³ \end{align}$$使用以 \(x_0 = 0\) 为中心的这个截断泰勒级数,我们可以近似 \(f(x)\) = sin \(x\) 在 \(x=2\) 处的值。要做到这一点,我们只需将 \(x = 2\) 代入上述四阶泰勒多项式的公式,得到$$\begin{align} \sin(2) &\approx 2 - \frac{1}{6} 2³ \ &\approx 2 - \frac{8}{6} \ &\approx \frac{2}{3} \end{align}.$$我们总是可以使用更高阶的泰勒多项式来进行估计。以我们推导 cos \(x\) 的闭式表达式的方式类似,我们可以写出 sin \(x\) 的泰勒级数$$ \sin x = \sum_{k=0}^{\infty} \frac{(-1)k}{(2k+1)!}x $$
泰勒级数误差
截断泰勒级数的误差界
假设 \(f(x)\) 是 \(x\) 的 \(n+1\) 阶可微函数,且 \(T_n(x)\) 是以 \(x_0\) 为中心的 \(f(x)\) 的 \(n\) 阶泰勒多项式。那么当 \(h = |x-x_0| \to 0\) 时,我们通过 $$ \left|f(x)-T_n(x)\right|\le C \cdot h^{n+1} = O(h^{n+1}) $$ 获得截断误差界
我们将在下一节中看到 \(C\) 的确切表达式:泰勒余项定理。
泰勒余项定理
假设 \(f(x)\) 是 \(x\) 的 \(n+1\) 阶可微函数。令 \(R_n(x)\) 表示 \(f(x)\) 与以 \(x_0\) 为中心的 \(f(x)\) 的 \(n\) 阶泰勒多项式之间的差。那么
对于某个位于 \(x\) 和 \(x_0\) 之间的 \(\xi\)。因此,上述提到的常数 \(C\) 是
.
注意,这个值等同于泰勒级数的下一个项。
误差的渐近行为
假设我们使用 \(t_n(x)\) 来近似 \(f(x)\)。假设给定的区间是 \(h_1\),它在 \(x_0\) 和 \(x\) 之间,并且与之相关的误差是 \(e_1\)。假设我们还有另一个区间 \(h_2\),我们需要找到与之相关的误差 \(e_2\)。
使用公式 \(e = O(h^{n+1})\),我们得到
示例
误差界限示例
假设我们想要使用关于点 \(x_0 = 0\) 的 4 次泰勒多项式来近似 \(f(x) = \sin x\)。我们将如何根据泰勒余项定理计算这个近似的误差界限?
对于某个 \(\xi\),它在 \(x_0\) 和 \(x\) 之间。
答案
如果我们想要找到绝对误差的上界,我们正在寻找 $ \vert f^{(5)}(\xi)\vert $ 的上界。
由于 $ f^{(5)}(x) = \cos x $
$ |f^{(5)}(\xi)|\le \cos(0) \rightarrow |f^{(5)}(\xi)|\le 1 $
然后:
$ |R_4(x)| = \left|\frac{f^{(5)}(\xi)}{5!} (x-x_0)^{5}\right| = \frac{|f^{(5)}(\xi)|}{5!} |x|^{5} \le \frac{1}{120} |x|^{5} $
误差预测示例
假设你将 \(\sqrt{x - 10}\) 在中心 \(x_0 = 12\) 的 3 次泰勒多项式中展开。对于 \(h_1 = 0.5\),你发现泰勒截断误差大约是 \(10^{-4}\)。你将如何找到 \(h_2 = 0.25\) 的泰勒截断误差?
答案
我们可以使用公式 \(e_2 = (\frac{h_2}{h_1})^{n+1}e_1\) 来找到 \(h_2 = 0.25\) 时的泰勒截断误差。
这里,\(n = 3\),因此 \(e_2 = (\frac{0.25}{0.5})^{4} \cdot 10^{-4} = 0.625 \cdot 10^{-5}\).
复习问题
-
泰勒级数的一般形式是什么?
-
你如何使用泰勒级数来近似一个给定点的函数?
-
你如何使用泰勒级数来近似一个函数的导数?
-
你如何使用泰勒级数来近似一个函数的积分?
-
给定一个函数和一个中心,你能写出 n-次泰勒多项式吗?
-
对于一个 n-次泰勒多项式,你的近似误差作为中心距离的函数的界限是什么?
-
对于简单函数,你能在泰勒误差界限中找到常数 C 吗?
-
能够确定为了使泰勒级数近似误差小于某个给定值,需要多少项。
更新日志
-
2025 年 2 月 18 日:Kaiyao Ke (kaiyaok2) — 修复渲染错误
-
2024 年 3 月 29 日:Dev Singh (dsingh14) — 在泰勒级数误差界限和近似中添加了说明
-
2024 年 3 月 27 日:Arnav Aggarwal (arnava4) — 将笔记与幻灯片对齐并添加了额外的示例
查看剩余条目
+ 2022 年 1 月 25 日:Arnav Shah (arnavss2) — 从幻灯片中添加错误预测
+ 2021 年 1 月 20 日:Mariana Silva (mfsilva) — 删除 FD 内容
+ 2020 年 2 月 10 日:Peter Sentz (sentz2) — 纠正一些小错误并更新一些符号
+ 2019 年 1 月 29 日:John Doherty (jjdoher2) — 从 F18 活动添加有限差分章节
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 删除演示链接
+ 2017 年 11 月 2 日:Erin Carrier (ecarrie2) — 添加变更日志
+ 2017 年 10 月 27 日:Yu Meng (yumeng5) — 首次完整草案
+ 2017 年 10 月 27 日:Erin Carrier (ecarrie2) — 添加复习问题,全文进行小修
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概述
作者
- CS 357 课程工作人员
随机数生成器和蒙特卡洛方法
原文:
cs357.cs.illinois.edu/textbook/notes/random-monte-carlo.html
学习目标
-
理解随机数生成器的特性以及随机数生成器中期望的特性。
-
给出使用蒙特卡洛方法的例子。
-
描述蒙特卡洛方法的误差。
随机数生成器
随机数生成器 (RNG) 是一种算法或方法,可以用来生成一组无法合理预测的数字序列。通常有两种主要的随机数生成方法:真随机方法和伪随机方法。真随机方法根据某些随机物理现象生成数字。例如,掷一个公平的骰子将生成 1 到 6 之间的真随机数。其他示例来源包括大气噪声和热噪声。伪随机方法使用计算算法生成看似随机的结果序列,实际上是可以预测和可重复的。
当使用伪随机方法时,由于计算机只能表示有限数量的数字,任何生成的序列最终都会重复。伪随机数生成器的周期定义为序列无重复前缀的最大长度。
随机数生成器的特性
随机数生成器具有以下特性:
-
随机模式:通过随机性的统计测试。
-
效率:执行速度快,存储需求小。
-
长周期:在重复之前尽可能长。
-
可重复性:如果以相同的初始条件启动,则会产生相同的序列。
-
可移植性:在不同的计算机上运行,并且能够在每个计算机上产生相同的序列。
线性同余生成器
一个线性同余生成器 (LCG) 是一种伪随机数生成器,其形式为:
其中\(a\)(乘数)和\(c\)(增量)是给定的整数,\(x_0\)被称为种子。LCG 的周期不能超过\(M\)(模数)。周期可能小于\(M\),这取决于\(a\)和\(c\)的值。质量取决于\(a\)和\(c\)。
LCG 的示例
下面是 Python 代码示例,展示了一个 LCG,它根据初始种子\(1\)生成数字\(1,3,7,5,1,3,7,5,\dots\)。为了遵循模式,我们将前一个数字翻倍,加\(1\),然后对\(10\)取模,因此\(a=2\),\(c=1\),\(M=10\)。
def lcg_gen_next(modulus: int, a: int, c: int, xk: int) -> int:
""" Uses an LCG to generate a pseudo-random number.
Args:
modulus (int): the period of the LCG
a (int): the multiplier
c (int): the increment
xk (int): the previously generated random number(or the seed)
Returns:
int: the next pseudo-random number, xk_p1
"""
xk_p1 = (a * xk + c) % modulus
return xk_p1
x = 1 # initial seed M = 10
a = 2
c = 1
for i in range(100):
print(x)
x = lcg_gen_next(M, a, c, x)
随机变量
一个随机变量 \(X\) 可以被视为一个函数,它将不可预测(随机)过程的输出映射到数值。如果你有先前的统计学经验,你可能会熟悉这个概念。
随机变量的例子包括:
-
明天我们会下多少雨?
-
我的黄油面包会正反面朝下吗?
我们没有确切的数字来表示这些随机过程,但我们可以通过大数定律来近似随机变量的长期结果。
离散随机变量
每个离散随机变量 \(X\) 可以取一个离散值 \(x_i\),其概率为 \(p_i\),对于 \(i = 1,…m\),且 \(\Sigma_{i=1}^m p_i = 1\)(即可能值是可数的)。这与连续随机变量形成对比,连续随机变量的可能值是不可数的无限多。
离散随机变量的期望值
离散随机变量的期望值 \(E(x)\) 定义为 \(\Sigma_{i=1}^m p_i x_i\)。这个概念可以被视为“平均结果”。
离散随机变量的例子:硬币投掷
考虑一个随机变量 \(X\),它是硬币投掷的结果,可以是正面或反面。
对于每一次投掷,\(x_i\) 是 \(0\) 或 \(1\),并且每个 \(x_i\) 的概率 \(p_i=0.5\)。
这个硬币投掷的期望值是多少?
答案
对于硬币投掷,期望值是 $ E(X) = 1 \cdot 0.5 + 0 \cdot 0.5 = 0.5$。
现在,假设我们投掷一枚“公平”的硬币 1000 次,并记录得到正面的次数。如果我们运行这个 \(1000\) 次硬币投掷实验 \(N\) 次(比如说 \(N=100\)),分布会是什么样子?
答案
每次进行 1000 次硬币投掷实验所记录的数字可能会接近期望值 \(0.5\)。进行实验 \(N\) 次的结果将看起来像正态分布,大多数结果接近 \(0.5\)。这也被称为大数定律(当 \(N\) 很大时)。
Monte Carlo
Monte Carlo 方法 是依赖于重复随机采样来近似所需量的算法。Monte Carlo 方法通常用于模拟以下类型的问题:
-
非确定性过程,
-
复杂的确定性系统和高维度的确定性问题(例如,非平凡函数的积分)。
Monte Carlo 最常见的一个应用是近似给定形状的面积/体积。例如,为了近似圆的面积,我们可以在圆周围的正方形区域内均匀地采样大量点。然后,我们检查哪些点在圆内,以得到圆内点的百分比 \(p\)。最后,我们将 \(p\) 乘以正方形的面积来近似圆的面积。Monte Carlo 在这种情况下之所以有效,是因为:
-
均匀随机采样意味着我们确保点在整个区域内分散并覆盖良好
-
根据大数定律,随着样本数量的增加,平均面积值将收敛到真实面积值。因此,使用大量的样本可以提高我们的估计。
Monte Carlo 积分
考虑使用蒙特卡洛方法估计积分 \(I = \int_a^b f(x) dx\)。设 \(X\) 是在 \([a, b]\) 上均匀分布的随机变量。那么,\(I = (b-a) \mathbb{E}[f(X)]\)。使用蒙特卡洛方法并取 \(n\) 个样本,我们估计的期望值是:
因此,积分的近似值是:
根据大数定律,当 \(n \to \infty\) 时,样本平均值 \(S_n\) 将收敛到期望值 \(\mathbb{E}[f(X)]\)。因此,当 \(n \to \infty\) 时,\(I_n \to \int_a^b f(x) dx\)。
根据中心极限定理,当 \(n \to \infty\) 时,
其中 \(N(0, \sigma²)\) 是正态分布;\(\mu = \mathbb{E}[f(X)]\) 和 \(\sigma² = Var[X]\)。
错误/收敛性
设 \(Z\) 是具有正态分布 \(N(0, \sigma²)\) 的随机变量。那么蒙特卡洛估计的误差 \(err = S_n - \mu\) 可以表示为
当 \(n \to \infty\) 时。
因此,蒙特卡洛方法的渐近行为是 \(\mathcal{O}(\frac{1}{\sqrt{n}})\),其中 \(n\) 是样本数量。
示例:应用蒙特卡洛
我们可以使用蒙特卡洛方法有效地近似复杂函数的定积分,这在高维空间中尤其有用,因为其他数值积分技术可能非常昂贵。以下是用 Python 代码近似函数 \(f(x,y) = x+y\) 在域 \([x_{min}, x_{max}] \times [y_{min}, y_{max}]\) 上的积分的代码:
import random
def f(x: float, y: float) -> float:
""" Returns the value for function *f* at point (x, y).
Args:
x: float: the point x.
y: float: the point y.
Returns:
float: f(x, y)
"""
return x + y
# set x_min, x_max, y_min and y_max for integral interval total = 0.0
# n is the number of points used in Monte Carlo integration for i in range(n):
x = random.uniform(x_min, x_max)
y = random.uniform(y_min, y_max)
total += f(x, y)
# estimated integral value est = (1.0/n * total)*((x_max-x_min)*(y_max-y_min))
复习问题
-
什么是伪随机数生成器?
-
好的随机数生成器的特性有哪些?
-
与使用真正的随机数相比,伪随机数生成器的优缺点是什么?
-
什么是线性同余发生器(LCG)?
-
随机数生成器的种子是什么?
-
随机数生成器会重复吗?它们是可复制的吗?
-
蒙特卡洛方法是什么?它们是如何使用的?
-
对于蒙特卡洛,误差与采样点数的关系如何?
-
给定蒙特卡洛计算值和采样误差,对于不同数量的样本,你期望的采样误差是多少?
-
对于一个小型示例问题,使用蒙特卡洛方法估计特定区域的面积。
-
对于一个小型示例问题,使用蒙特卡洛方法估计函数的积分。
更新日志
-
2024 年 2 月 17 日:Bhargav Chandaka (bhargav9) — 对内容进行重大重组,以与幻灯片/视频中的内容相匹配
-
2018 年 1 月 25 日:Yu Meng (yumeng5) — 第一份完整草案
-
2018 年 1 月 25 日:Erin Carrier (ecarrie2) — 全文小修,增加复习问题
查看剩余条目
+ 2018 年 1 月 17 日:Erin Carrier (ecarrie2) — 概述
作者
- CS 357 课程工作人员
向量、矩阵和范数
学习目标
-
理解向量空间
-
识别线性变换
-
识别特殊矩阵
-
执行矩阵-向量乘法
-
将线性变换表示为矩阵
-
计算向量和矩阵的范数
向量和向量空间
向量
一个 *向量* 是一个表示大小和方向的数字数组。一个 n 维向量有 n 个分量。向量是向量空间的一个元素。
示例
这是一个二维向量的例子。
具有唯一确定的标量 \(c_1,\dots,c_n\),集合 \({\mathbf{v}_1,\dots, \mathbf{v}_n}\) 被称为 \(V\) 的 *基。基的大小 \(n\) 被称为 \(V\) 的 *维度**。
向量空间的典型例子是 \(V=\mathbb{R}^n\),其中 \(F=\mathbb{R}\)。在 \(\mathbb{R}^n\) 中的向量可以表示为一个数字数组:
\(\mathbb{R}^n\) 的维度是 \(n\)。\(\mathbb{R}^n\) 的标准基向量可以表示为
一组向量 \(\mathbf{v}_1,\dots,\mathbf{v}_k\) 被称为 线性无关,如果方程 \(\alpha_1\mathbf{v}_1 + \alpha_2\mathbf{v}_2 + \dots + \alpha_k\mathbf{v}_k = \mathbf{0}\) 在未知数 \(\alpha_1,\dots,\alpha_k\) 中只有 平凡解 \(\alpha_1=\alpha_2 = \dots = \alpha_k = 0\)。否则,这些向量是 线性相关 的,并且至少有一个向量可以写成该集合中其他向量的线性组合。基总是线性无关的。
内积
令 \(V\) 为一个实向量空间。那么,一个 内积 是一个函数 \(\langle\cdot, \cdot \rangle: V \times V \rightarrow \mathbb{R}\)(即它接受两个向量并返回一个实数),它满足以下四个性质,其中 \(\mathbf{u}, \mathbf{v}, \mathbf{w} \in V\) 和 \(\alpha, \beta \in \mathbb{R}\):
-
正定性:\(\langle \mathbf{u}, \mathbf{u} \rangle \geq 0\)
-
正定性:\(\langle \mathbf{u}, \mathbf{u} \rangle = 0\) 当且仅当 \(\mathbf{u} = 0\)
-
对称性:\(\langle \mathbf{u}, \mathbf{v} \rangle = \langle \mathbf{v}, \mathbf{u} \rangle\)
-
线性:\(\langle \alpha \mathbf{u} + \beta \mathbf{v}, \mathbf{w} \rangle = \alpha \langle \mathbf{u}, w \rangle + \beta \langle \mathbf{v}, \mathbf{w} \rangle\)
内积直观地表示两个向量之间的相似性。如果 \(\langle \mathbf{u}, \mathbf{v} \rangle = 0\),则称向量 \(\mathbf{u}, \mathbf{v} \in V\) 为 正交。
在 \(\mathbb{R}^n\) 上的标准内积是点积:\(\langle \mathbf{x}, \mathbf{y}\rangle = \mathbf{x}^T\mathbf{y} = \sum_{i=1}^nx_i y_i.\)
有关 内积定义 的更多信息
线性变换和矩阵
两个向量空间 \(V\) 和 \(W\) 之间的函数 \(f: V \to W\) 被称为 线性,如果
-
\(f(\mathbf{u} + \mathbf{v}) = f(\mathbf{u}) + f(\mathbf{v})\),对于任何 \(\mathbf{u},\mathbf{v} \in V\)
-
\(f(c\mathbf{v}) = cf(\mathbf{v})\),对于所有 \(\mathbf{v} \in V\) 和所有标量 \(c\)
\(f\) 通常被称为 线性变换。
如果 \(n\) 和 \(m\) 分别是 \(V\) 和 \(W\) 的维度,那么 \(f\) 可以表示为一个 \(m\times n\) 的矩形数组或 矩阵
这里有一些重要的矩阵类型。
特殊矩阵
零矩阵
\(m \times n\) 的 零矩阵 表示为 \({\bf 0}_{mn}\) 并且所有项都等于零。例如,\(3 \times 4\) 的零矩阵是
单位矩阵
\(n \times n\) 的 单位矩阵 用 \({\bf I}_n\) 表示,除了对角线上的元素都为 1 之外,其余元素都为 0。例如,\(4 \times 4\) 的单位矩阵是
单位矩阵的性质:
任何方阵与其对应的单位矩阵相乘都会得到原始矩阵。
对角矩阵
一个 \(n \times n\) 的 对角矩阵 除了对角线元素外,其余元素都为零。我们通常用 \({\bf D}\) 表示对角矩阵。例如,\(4 \times 4\) 的对角矩阵具有以下形式
三角矩阵
一个 下三角矩阵 是一个上三角矩阵,其对角线以上的所有元素都是 0。我们通常用 \({\bf L}\) 表示下三角矩阵。例如,\(4 \times 4\) 的下三角矩阵具有以下形式
一个 上三角矩阵 是一个方阵,其对角线以下的元素都是 0。我们通常用 \({\bf U}\) 表示上三角矩阵。例如,\(4 \times 4\) 的上三角矩阵具有以下形式
三角矩阵的性质:
-
一个 \(n \times n\) 的三角矩阵有 \(n(n-1)/2\) 个必须为零的条目,以及 \(n(n+1)/2\) 个允许非零的条目。
-
零矩阵、单位矩阵和对角矩阵都是既是下三角矩阵又是上三角矩阵。
交换矩阵
一个 交换矩阵 是一个方阵,除了每行和每列中有一个元素为 1 之外,其余元素都为 0。我们通常用 \({\bf P}\) 表示交换矩阵。一个 \(4 \times 4\) 的交换矩阵的例子是
交换矩阵的性质:
-
精确地有 \(n\) 个条目不为零。
-
用一个交换矩阵乘以一个向量会重新排列向量中元素的顺序。例如,使用上面的 \({\bf P}\) 和 \(x = [1, 2, 3, 4]^T\),乘积是 \({\bf Px} = [2, 4, 1, 3]^T\)。
-
如果 \(P_{ij} = 1\),则 \(({\bf Px})_i = x_j\)。
-
置换矩阵的逆是其转置,所以 \({\bf PP}^T = {\bf P}^T{\bf P} = {\bf I}\)。
分块矩阵
分块形式 的矩阵是将矩阵划分为块的矩阵。块简单地是一个子矩阵。例如,考虑
其中 \({\bf A}\),\({\bf B}\),\({\bf C}\) 和 \({\bf D}\) 是子矩阵。
分块形式中也有特殊的矩阵。例如,块对角 矩阵是一个对角块为零矩阵的分块矩阵。
矩阵秩
矩阵的 秩 是矩阵中线性无关列的数量。也可以证明矩阵具有相同数量的线性无关行。如果 \(\mathbf{A}\) 是一个 \(m \times n\) 的矩阵,那么
-
\(\text{rank}(\mathbf{A}) \leq \text{min}(m,n)\)。
-
如果 \(\text{rank}(\mathbf{A}) = \text{min}(m,n)\),那么 \(\mathbf{A}\) 是 满秩 的。否则,\(\mathbf{A}\) 是 秩亏缺 的。
一个 \(n\times n\) 的方阵 \(\mathbf{A}\) 是 可逆的 如果存在一个方阵 \(\mathbf{B}\) 使得 \(\mathbf{AB} = \mathbf{BA} = \mathbf{I}\),其中 \(\mathbf{I}\) 是 \(n\times n\) 的单位矩阵。矩阵 \(\mathbf{B}\) 表示为 \(\mathbf{A}^{-1}\)。一个方阵是可逆的当且仅当它具有满秩。一个不可逆的方阵称为 奇异的 矩阵。
矩阵-向量乘法
设 \(\mathbf{A}\) 是一个 \(m\times n\) 的实数矩阵。我们也可以用 \(\mathbf{A}\in\mathbb{R}^{m\times n}\) 作为简写。如果 \(\mathbf{x}\) 是 \(\mathbb{R}^n\) 中的一个向量,那么矩阵-向量乘积 \(\mathbf{A}\mathbf{x} = \mathbf{b}\) 是一个 \(\mathbf{R}^m\) 中的向量,定义为:
我们可以有两种方式来解释矩阵-向量乘法。在整个在线教科书的参考中,我们将使用 \({\bf a}_i\) 来指代矩阵 \({\bf A}\) 的第 \(i\) 列,以及 \({\bf a}^T_i\) 来指代矩阵 \({\bf A}\) 的第 \(i\) 行。
- 将矩阵-向量乘法表示为 \({\bf A}\) 的行的内积:
- 将矩阵-向量乘法表示为 \({\bf A}\) 的列的线性组合:
\(\mathbf{A}\mathbf{x} = x_1\mathbf{a}_{1} + x_2\mathbf{a}_{2} + \dots x_n\mathbf{a}_{n} = x_1\begin{bmatrix}a_{11} \\ a_{21} \\ \vdots \\ a_{m1}\end{bmatrix} + x_2\begin{bmatrix}a_{12} \\ a_{22} \\ \vdots \\ a_{m2}\end{bmatrix} + \dots + x_n\begin{bmatrix}a_{1n} \\ a_{2n} \\ \vdots \\ a_{mn}\end{bmatrix}\)
正是这种表示法使我们能够用矩阵表达有限维向量空间之间的任何线性变换。
示例
执行矩阵-向量乘法 \({\bf Ax}\)。
答案
\(\begin{eqnarray} {\bf Ax} &=& \begin{bmatrix} 1 & 7 & 8 & 4\\ -5 & 3 & 2 & 2\\ 0 & 5 & 6 & 6\end{bmatrix} \begin{bmatrix}1 \\ 2 \\ 0 \\ -4\end{bmatrix} \\ \\ &=& 1 \begin{bmatrix} 1 \\ -5 \\ 0 \end{bmatrix} + 2 \begin{bmatrix} 7 \\ 3 \\ 5 \end{bmatrix} + 0 \begin{bmatrix} 8 \\ 2 \\ 6 \end{bmatrix} + -4 \begin{bmatrix} 4 \\ 2 \\ 6 \end{bmatrix} \\ \\ &=& \begin{bmatrix} 1 \\ -5 \\ 0 \end{bmatrix} + \begin{bmatrix} 14 \\ 6 \\ 10 \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \\ 0 \end{bmatrix} + \begin{bmatrix} -16 \\ -8 \\ -24 \end{bmatrix} \\ \\ &=& \begin{bmatrix} 1 + 14 + 0 -16 \\ -5 + 6 + 0 - 8\\ 0 + 10 + 0 - 24\end{bmatrix} \\ \\ &=& \begin{bmatrix} -1 \\ -7\\ -14\end{bmatrix} \end{eqnarray}\)
线性变换的矩阵表示
设 \(\mathbf{e}_1,\mathbf{e}_2,\dots,\mathbf{e}_n\) 为 \(\mathbb{R}^n\) 的标准基。如果我们定义向量 \(\mathbf{z}_j = \mathbf{A}\mathbf{e}_j\),那么利用矩阵-向量乘积作为 \(\mathbf{A}\) 的列的线性组合的解释,我们有:
其中,我们将 \(\mathbb{R}^m\) 的标准基写为 \(\hat{\mathbf{e}}_1,\hat{\mathbf{e}}_2,\dots,\hat{\mathbf{e}}_m\)。
换句话说,如果 \(\mathbf{z}_j = \mathbf{A}\mathbf{e}_j\) 被写成 \(\mathbb{R}^m\) 的基向量的线性组合,那么元素 \(a_{ij}\) 是对应于 \(\hat{\mathbf{e}}_{i}\) 的系数。
示例
假设 \(V\) 是一个由 \(\mathbf{v}_1,\mathbf{v}_2,\mathbf{v}_3\) 构成的向量空间,而 \(W\) 是一个由 \(\mathbf{w}_1,\mathbf{w}_2\) 构成的向量空间。那么 \(V\) 和 \(W\) 的维度分别是 3 和 2。因此,任何线性变换 \(f: V \to W\) 都可以表示为一个 \(2\times 3\) 的矩阵。我们可以引入列向量表示法,使得向量 \(\mathbf{v} = \alpha_1\mathbf{v}_1 + \alpha_2\mathbf{v}_2 + \alpha_3\mathbf{v}_3\) 和 \(\mathbf{w} = \beta_1\mathbf{w}_1 + \beta_2\mathbf{w}_2\) 可以写成
我们没有指定向量空间 \(V\) 和 \(W\) 的具体内容,但如果我们将它们视为 \(\mathbb{R}³\) 和 \(\mathbb{R}²\) 的元素,那就没问题。
假设以下关于线性变换 \(f\) 的性质是已知的:
-
\(f(\mathbf{v}_1) = \mathbf{w}_1\)
-
\(f(\mathbf{v}_2) = 5\mathbf{w}_1 - \mathbf{w}_2\)
-
\(f(\mathbf{v}_3) = 2\mathbf{w}_1 + 2\mathbf{w}_2\)
使用上述提供的信息,确定 \(f\) 的矩阵表示。
答案
第一个方程告诉我们 $ \mathbf{w}1 = f(\mathbf{v}1) \implies \begin{bmatrix} 1 \ 0\end{bmatrix} = \begin{bmatrix} a & a & a_{13}\ a_{21} & a_{22} & a_{23}\end{bmatrix}\begin{bmatrix} 1 \ 0 \ 0\end{bmatrix} = \begin{bmatrix} a_{11} \ a_{21} \end{bmatrix}. $ 因此我们知道 \(a_{11} = 1,\ a_{21} = 0.\) 第二个方程告诉我们 $ 5\mathbf{w}1 - \mathbf{w}2 = f(\mathbf{v}2) \implies \begin{bmatrix} 5 \ -1\end{bmatrix} = \begin{bmatrix} 1 & a & a\ 0 & a & a_{23}\end{bmatrix}\begin{bmatrix} 0 \ 1 \ 0\end{bmatrix} = \begin{bmatrix} a_{12} \ a_{22} \end{bmatrix}. $ 因此我们知道 \(a_{12} = 5,\ a_{22} = -1.\) 最后,第三个方程告诉我们 $ 2\mathbf{w}1 + 2\mathbf{w}2 = f(\mathbf{v}2) \implies \begin{bmatrix} 2 \ 2\end{bmatrix} = \begin{bmatrix} 1 & 5 & a\ 0 & -1 & a\end{bmatrix}\begin{bmatrix} 0 \ 0 \ 1\end{bmatrix} = \begin{bmatrix} a \ a_{23} \end{bmatrix}. $ 因此,\(a_{13} = 2,\ a_{23} = 2\),线性变换 \(f\) 可以表示为矩阵:$ \begin{bmatrix} 1 & 5 & 2\ 0 & -1 & 2\end{bmatrix}. $ 重要的是要注意,矩阵表示不仅取决于 \(f\),还取决于我们选择的基。如果我们为向量空间 \(V\) 和 \(W\) 选择不同的基,\(f\) 的矩阵表示也会改变。
矩阵作为算子
旋转算子
这个旋转矩阵以逆时针方向旋转点 \(\theta\)。
缩放算子
缩放算子将点在 x 方向上按 a 缩放或缩小,在 y 方向上按 b 缩放或缩小。
反射算子
反射矩阵将点沿 x 或 y 轴反射。以下示例展示了点沿 x 和 y 轴的反射。
平移算子
平移或平移算子将点在 x 方向上移动 a 个单位,在 y 方向上移动 b 个单位。这不是一个线性变换。
向量范数
向量范数是一个函数 \(\| \mathbf{u} \|: V \rightarrow \mathbb{R}^+_0\)(即,它接受一个向量并返回一个非负实数),它满足以下性质,其中 \(\mathbf{u}, \mathbf{v} \in V\) 且 \(\alpha \in \mathbb{R}\):
-
正定性:\(\| \mathbf{u}\| \geq 0\)
-
正定性:\(\|\mathbf{u}\| = 0\) 当且仅当 \(\mathbf{u} = \mathbf{0}\)
-
同质性:\(\|\alpha \mathbf{u}\| = \vert\alpha\vert \|\mathbf{u}\|\)
-
三角不等式:\(\|\mathbf{u} + \mathbf{v}\| \leq \|\mathbf{u}\| + \|\mathbf{v}\|\)
范数是“绝对值”的推广,用于衡量输入向量的“大小”。
p-范数
p-范数定义为
\(\|\mathbf{w}\|_p = (\sum_{i=1}^N \vert w_i \vert^p)^{\frac{1}{p}}\).
当\(p \geq 1\)时,定义是一个有效的范数。如果\(0 \leq p < 1\),则它不是一个有效的范数,因为它违反了三角不等式。
当\(p=2\)(2-范数)时,这被称为欧几里得范数,它对应于向量的长度。
向量范数示例
考虑\(\mathbf{w} = [-3, 5, 0, 1]\)的情况。计算\(\mathbf{w}\)的 1,2 和\(\infty\)范数。
答案
对于 1-范数:\(\|\mathbf{w}\|_1 = (\sum_{i=1}^N |w_i|¹)^{\frac{1}{1}}\) \(\|\mathbf{w}\|_1 = \sum_{i=1}^N |w_i|\) \(\|\mathbf{w}\|_1 = |-3| + |5| + |0| + |1|\) \(\|\mathbf{w}\|_1 = 3 + 5 + 0 + 1\) \(\|\mathbf{w}\|_1 = 9\) 对于 2-范数:\(\|\mathbf{w}\|_2 = (\sum_{i=1}^N |w_i|²)^{\frac{1}{2}}\) \(\|\mathbf{w}\|_2 = \sqrt{\sum_{i=1}^N w_i²}\) \(\|\mathbf{w}\|_2 = \sqrt{(-3)² + (5)² + (0)² + (1)²}\) \(\|\mathbf{w}\|_2 = \sqrt{9 + 25 + 0 + 1}\) \(\|\mathbf{w}\|_2 = \sqrt{35} \approx 5.92\) 对于\(\infty\)-范数:\(\|\mathbf{w}\|_\infty = \lim_{p\to\infty}(\sum_{i=1}^N |w_i|^p)^{\frac{1}{p}}\) \(\|\mathbf{w}\|_\infty = \max_{i=1,\dots,N} |w_i|\) \(\|\mathbf{w}\|_\infty = \max(|-3|, |5|, |0|, |1|)\) \(\|\mathbf{w}\|_\infty = \max(3, 5, 0, 1)\) \(\|\mathbf{w}\|_\infty = 5\)
范数与误差
在计算向量结果时计算误差,可以应用范数。
注意: 范数不是可加的
\(\|\mathbf{True\ Value} - \mathbf{Approximate\ Value}\|\\ \neq \|\mathbf{True\ Value} \| - \|\mathbf{Approximate\ Value} \|\)
示例
根据上述真实向量和近似向量计算 1-范数误差。
答案
\(\begin{eqnarray} 绝对误差 &=& \left\|\begin{bmatrix} 0 \\ 6 \\ -4 \end{bmatrix} - \begin{bmatrix} 0 \\ 5 \\ -3 \end{bmatrix}\right\|_{1}\\ \\ &=& \left\|\begin{bmatrix} 0 \\ 1 \\ -1 \end{bmatrix}\right\|_{1}\\ \\ &=& |0| + |1| + |-1|\\ \\ &=& 2 \end{eqnarray}\) \(\begin{eqnarray} 相对误差 &=& \frac{\left\|\begin{bmatrix} 0 \\ 6 \\ -4 \end{bmatrix} - \begin{bmatrix} 0 \\ 5 \\ -3 \end{bmatrix}\right\|_{1}}{\left\|\begin{bmatrix} 0 \\ 6 \\ -4 \end{bmatrix}\right\|_{1}}\\ \\ &=& \frac{2}{|0| + |6| + |-4|}\\ \\ &=& \frac{2}{10}\\ \\ &=& \frac{1}{5}\\ \\ \end{eqnarray}\)
矩阵范数
一个 通用矩阵范数 是一个满足以下性质的实值函数 \(\| {\bf A} \|\):
-
正定性:\(\|{\bf A}\| \geq 0\)
-
正定性:\(\|{\bf A}\| = 0\) 当且仅当 \({\bf A} = 0\)
-
同质性:对于所有标量 \(\lambda\),\(\|\lambda {\bf A}\| = \vert\lambda\vert \|{\bf A}\|\)
-
三角不等式:\(\|{\bf A} + {\bf B}\| \leq \|{\bf A}\| + \|{\bf B}\|\)
诱导(或算子)矩阵范数 与特定的向量范数 \(\| \cdot \|\) 相关,并定义为:
诱导矩阵范数是一般矩阵范数的特定类型。诱导矩阵范数告诉我们任何向量乘以矩阵时范数的最大放大倍数。注意,上述定义与以下定义等价
除了上述一般矩阵范数的性质外,诱导矩阵范数还满足以下子乘性条件:
Frobenius 范数
Frobenius 范数简单地是矩阵中每个平方元素的平方和的平方根,这相当于将向量 \(2\)-范数应用于展平的矩阵,
Frobenius 范数是通用矩阵范数的一个例子,它不是诱导范数。
示例
计算矩阵 \({\bf Q}\) 的 Frobenius 范数。
答案
\(\begin{eqnarray} \|{\bf Q}\|_{\bf F} &=& \sqrt{1² + 4² + 6² + 5²}\\ &=& \sqrt{78}\\ &\approx& 8.83 \end{eqnarray}\)
矩阵 p-范数
矩阵 p-范数是由向量的 p-范数诱导的。它是
有三种特殊情况:
1-范数
1-范数简化为矩阵的最大绝对列和,即,
2-范数
2-范数简化为矩阵的最大奇异值。
\(\infty\)-范数
\(\infty\)-范数简化为矩阵的最大绝对行和。
示例
计算矩阵 \({\bf C}\) 的 1-范数、2-范数和 \(\infty\)-范数。
答案
矩阵\(\bf C\)的列和的绝对值是 $ |3| + |-1| = 4, |-2| + |3| = 5. $ 因此,\(\begin{eqnarray} \|{\bf C}\|_1 &=& \max (4, 5)\\ &=& 5\. \end{eqnarray}\) 稀疏值是矩阵 \({\bf C}^T {\bf C}\) 的特征值的平方根。你还可以通过计算矩阵的奇异值分解来找到最大的奇异值。\(\|{\bf C}\|_2 = \max_{\|\mathbf{x}\|_2=1} \|{\bf C}\mathbf{x}\|_2\) \(det({\bf C}^T {\bf C} - \lambda {\bf I}) = 0\) $ det( \begin{bmatrix} 3 & -1 \ -2 & 3 \ \end{bmatrix} \begin{bmatrix} 3 & -2 \ -1 & 3 \ \end{bmatrix} - \lambda {\bf I}) = 0 $ $ det( \begin{bmatrix} 9+1 & -6-3 \ -3-6 & 4+9 \ \end{bmatrix} - \lambda {\bf I}) = 0 $ $ det( \begin{bmatrix} 10 - \lambda & -9 \ -9 & 13 - \lambda \ \end{bmatrix} ) = 0 $ \((10-\lambda)(13-\lambda) - 81 = 0\) \(\lambda² - 23\lambda + 130 - 81 = 0\) \(\lambda² - 23\lambda + 49 = 0\) \((\lambda-\frac{1}{2}(23+3\sqrt{37}))(\lambda-\frac{1}{2}(23-3\sqrt{37})) = 0\) \(\|{\bf C}\|_2 = \sqrt{\lambda_{max}} = \sqrt{\frac{1}{2}(23+3\sqrt{37})} \approx 4.54.\) 矩阵\(\bf C\)的行和的绝对值是 $ |3| + |-2| = 5, |-1| + |3| = 4. $ 因此,\(\begin{eqnarray} \|{\bf C}\|_{\infty} &=& \max (4, 5)\\ &=& 5\. \end{eqnarray}\)
复习问题
-
什么是向量空间?
-
内积是什么?
-
给定一个特定的函数\(f(\mathbf{x})\),\(f(\mathbf{x})\)可以被认为是内积吗?
-
什么是向量范数?(一个函数要成为向量范数必须满足哪些性质?)
-
给定一个特定的函数\(f(\mathbf{x})\),\(f(\mathbf{x})\)可以被认为是范数吗?
-
诱导矩阵范数的定义是什么?它们测量什么?
-
诱导矩阵范数满足哪些性质?哪些是次可乘性质?能够应用所有这些性质。
-
对于一个诱导矩阵范数,给定\(\|\mathbf{x}\|\)和\(\|{\bf A}\mathbf{x}\|\)对于几个向量,你能确定\(\|{\bf A}\|\)的下界吗?
-
什么是 Frobenius 矩阵范数?
-
对于给定的向量,计算向量的 1,2 和\(\infty\)范数。
-
对于给定的矩阵,计算矩阵的 1,2 和\(\infty\)范数。
-
了解特殊矩阵的规范(例如,对角矩阵、正交矩阵等的范数)
脚注
- 在一个凸空间(实数和复数都是)上。
更新日志
-
2025 年 10 月 2 日:Dev Singh(dsingh14)——修复范数计算中的错误
-
2024 年 2 月 20 日:Dev Singh(dsingh14)——添加关于范数可加性的警告
-
2024 年 2 月 17 日:Apramey Hosahalli(apramey2)——添加错误示例,格式化矩阵 p-范数示例
查看剩余条目
+ 2024 年 2 月 16 日:陈宇轩(yuxuan19)——改进示例结构,更新了复习问题
+ 2024 年 2 月 15 日:Apramey Hosahalli(apramey2)——改进过渡,添加了矩阵向量乘法的示例,以及矩阵作为算子的简要说明
+ 2024 年 2 月 13 日:Apramey Hosahalli (apramey2) — 为向量添加章节,并为 Frobenius 范数和 p-范数章节添加示例
+ 2024 年 2 月 10 日:Apramey Hosahalli (apramey2) — 根据讲座顺序重新排列章节并更改学习目标
+ 2022 年 3 月 1 日:Arnav Shah (arnavss2) — 添加了规范和误差章节
+ 2022 年 2 月 22 日:Arnav Shah (arnavss2) — 添加了矩阵作为算子的章节
+ 2020 年 4 月 27 日:Mariana Silva (mfsilva) — 更新了符号和矩阵-向量章节
+ 2020 年 2 月 1 日:Peter Sentz () — 从当前幻灯片添加更多文本
+ 2018 年 3 月 14 日:Adam Stewart (adamjs5) — 阐明 Frobenius 范数的定义
+ 2017 年 11 月 10 日:Erin Carrier (ecarrie2) — 修复示例的索引范围,添加线性函数定义
+ 2017 年 10 月 29 日:Erin Carrier (ecarrie2) — 添加块形式
+ 2017 年 10 月 29 日:Erin Carrier (ecarrie2) — 添加复习问题,完成向量空间定义,重写矩阵范数章节,进行其他小修订
+ 2017 年 10 月 29 日:Erin Carrier (ecarrie2) — 更改内积符号,对诱导范数与一般范数进行额外评论
+ 2017 年 10 月 28 日:John Doherty (jjdoher2) — 第一份完整草案
+ 2017 年 10 月 16 日:Matthew West (mwest) — 第一份完整草案
作者
- CS 357 课程工作人员
LU 分解求解线性方程
学习目标
-
理解线性方程组的使用。
-
使用已知数据为实际问题设置线性方程组。
-
描述矩阵 \({\bf A} = {\bf LU}\) 的分解。
-
比较 LU 分解与其他操作(如矩阵-矩阵乘法)的成本。
-
实现 LU 分解算法。
-
给定 \({\bf A}\) 的 LU 分解,求解方程组 \({\bf Ax} = {\bf b}\)。
-
给出需要行交换的矩阵的例子。
-
实现 LUP 分解算法。
-
手动计算 LU 和 LUP 分解。
-
使用库函数计算并使用 LU 分解。
基本思想:线性操作的“撤销”按钮
矩阵-向量乘法:给定数据 \({\bf x}\) 和算子 \({\bf A}\),我们可以找到 \({\bf y}\) 使得 \({\bf y = Ax}\):
如果我们知道 \({\bf y}\) 但不知道 \({\bf x}\) 会怎样?我们需要“撤销”转换:
示例:撤销转换
假设我们已知算子 \({\bf A}\),已知数据 \({\bf y}\),以及满足关系 \({\bf y = Ax}\) 的未知数据 \({\bf x}\)。\({\bf A}\) 和 \({\bf y}\) 的值如下所示。
我们如何求解 \(\textbf{x} = [x_1, x_2]^T\)?
答案
我们构建以下线性方程组:$ \begin{cases} x_1 + 2x_2 = 5\ 3x_1 + 4x_2 = 11 \end{cases} \hspace{5mm} $ 然后解为:$ \begin{cases} x_1 = 1\ x_2 = 2 \end{cases} \hspace{5mm} \text{,或者} \hspace{5mm} \textbf{x} = \begin{bmatrix} 1 \ 2 \end{bmatrix} $
示例:图像模糊与恢复
原始图像显示 SSN 号码存储为介于 \(0\) 和 \(1\) 之间的实数 \(2D\) 数组(\(0\) 表示白色像素,\(1\) 表示黑色像素)。它有 \(40\) 行像素和 \(100\) 列像素。我们可以将 \(2D\) 数组展平为包含 \(1D\) 数据的 \(1D\) 数组 \(\bf{x}\),其维度为 \(4000\)。然后我们可以对数据 \(\bf{x}\) 应用模糊操作,即
其中 \(\bf{A}\) 是模糊算子,\(\bf{y}\) 是模糊图像:

要“撤销”模糊以恢复原始图像,我们使用模糊算子 \(\bf{A}\) 和模糊图像 \(\bf{y}\) 求解线性方程组。以下图表显示了当 \(\bf{y}\) 没有任何噪声(“干净数据”)时的转换:

在一定程度上,也有可能从带有噪声的 \(\bf{x}\) 中恢复:

要回答“我们能够添加多少噪声,仍然能够从原始图像中恢复有意义的信息?”以及“在哪个点上这种逆变换失败?”这些问题,我们需要了解本课程后面将介绍的“撤销”操作敏感性信息。
上三角系统的后向替换算法
要实际求解 \({\bf A x} = {\bf b}\),我们可以从一个“更简单”的方程组开始。让我们考虑三角矩阵——后向替换算法解决了 \({\bf U x} = {\bf b}\) 的线性系统,其中 \({\bf U}\) 是一个上三角矩阵。
上三角线性系统 \({\bf U}{\bf x} = {\bf b}\) 可以写成矩阵形式:
注意到上三角系统 \({\bf U}x = b\) 可以写成以下线性方程组:
后向替换解法从下往上工作,得到:
因此,解的一般形式是:
注意到有 \(n\) 次除法,\(\frac{n(n-1)}{2}\) 次减法/加法,以及 \(\frac{n(n-1)}{2}\) 次乘法,因此计算复杂度是 \(\bf{O(n²)}\)。
或者,我们也可以将 \({\bf U}x = b\) 写成 \(\bf{U}\) 的列的线性组合:
后向替换算法的性质是:
-
如果任何对角元素 \(U_{ii}\) 为零,则该系统是奇异的,无法求解。
-
如果 \({\bf U}\) 的所有对角元素都不为零,则该系统有唯一解。
-
后向替换算法的操作次数为 \(O(n²)\),当 \(n \to \infty\) 时。
解决 \({\bf U x} = {\bf b}\) 的后向替换算法的代码是:
import numpy as np
def back_sub(U, b):
"""x = back_sub(U, b) is the solution to U x = b
U must be an upper-triangular matrix
b must be a vector of the same leading dimension as U
"""
n = U.shape[0]
x = np.zeros(n)
for i in range(n-1, -1, -1):
tmp = b[i]
for j in range(i+1, n):
tmp -= U[i,j] * x[j]
x[i] = tmp / U[i,i]
return x
示例:上三角系统的后向替换
我们如何求解 \(x = [x_1, x_2, x_3, x_4]^T\)?
答案
$ 2x_4 = 4 \Rightarrow x_4 = \frac{4}{2} = 2 $ $ 6x_3 + 4x_4 = 6 \Rightarrow x_3 = \frac{6 - 4(2)}{6} = -\frac{1}{3} $ $ 2x_2 + 2x_3 + 3x_4 = 2 \Rightarrow x_2 = \frac{2 - 2(-\frac{1}{3}) - 3(2)}{2} = -\frac{5}{3} $ $ 2x_1 + 3x_2 + x_3 + x_4 = 2 \Rightarrow x_1 = \frac{2 - 3(-\frac{5}{3}) - (-\frac{1}{3}) - 2}{2} = \frac{8}{3} $
下三角系统前向替换算法
前向替换算法解决了线性系统 \({\bf Lx} = {\bf b}\),其中 \({\bf L}\) 是一个下三角矩阵。它是回代法的逆过程。
下三角线性系统 \({\bf L}{\bf x} = {\bf b}\) 可以写成矩阵形式:
这也可以写成以下线性方程组:
前向替换算法通过从上到下工作并依次求解每个变量来解决下三角线性系统。在数学上,这表示为:
因此,解的一般形式是:
注意,这里也有 \(n\) 次除法,\(\frac{n(n-1)}{2}\) 次减法/加法,以及 \(\frac{n(n-1)}{2}\) 次乘法,因此计算复杂度为 \(\bf{O(n²)}\)。
前向替换算法的性质:
-
如果矩阵 \({\bf L}\) 的任何对角元素 \(L_{ii}\) 为零,则该系统是奇异的,无法求解。
-
如果矩阵 \({\bf L}\) 的所有对角元素均非零,则该系统有唯一解。
-
当 \(n \to \infty\) 时,前向替换算法的操作次数为 \(O(n²)\)。
解决 \({\bf L x} = {\bf b}\) 的前向替换算法的代码是:
import numpy as np
def forward_sub(L, b):
"""x = forward_sub(L, b) is the solution to L x = b
L must be a lower-triangular matrix
b must be a vector of the same leading dimension as L
"""
n = L.shape[0]
x = np.zeros(n)
for i in range(n):
tmp = b[i]
for j in range(i):
tmp -= L[i,j] * x[j]
x[i] = tmp / L[i,i]
return x
示例:下三角系统的前向替换
我们如何求解 \(x = [x_1, x_2, x_3, x_4]^T\)?
答案
$ 2x_1 = 2 \Rightarrow x_1 = 1 $ $ 3x_1 + 2x_2 = 2 \Rightarrow x_2 = \frac{2-3}{2} = -0.5 $ $ 1x_1 + 2x_2 + 6x_3 = 6 \Rightarrow x_3 = \frac{6-1+1}{6} = 1 $ $ 1x_1 + 3x_2 + 4x_3 + 2x_4 = 4 \Rightarrow x_4 = \frac{4-1+1.5-4}{2} = 0.25 $
LU 分解定义
当 \(\bf{A}\) 是一个非三角矩阵时,为了求解 \({\bf A x} = {\bf b}\),我们可以执行 LU 分解:给定一个 \(n \times n\) 的矩阵 \(\bf{A}\),矩阵 \({\bf A}\) 的 LU 分解 是一对矩阵 \({\bf L}\) 和 \({\bf U}\),使得:
-
\({\bf A} = {\bf LU}\)
-
\({\bf L}\) 是一个对角线元素都等于 1 的下三角矩阵
-
\({\bf U}\) 是一个上三角矩阵。
LU 分解的性质是:
-
矩阵 \({\bf A}\) 的 LU 分解可能不存在。
-
如果 LU 分解存在,则它是唯一的。
-
LU 分解提供了一种有效求解线性方程的方法。
-
\({\bf L}\) 的所有对角线元素都设置为 1 的原因是这意味着 LU 分解是唯一的。这种选择是有些任意的(我们本可以决定\({\bf U}\)的对角线必须为 1),但它是一个标准的选择。
-
我们使用“分解”和“因式分解”这两个术语可以互换,意味着将一个矩阵表示为两个或更多其他矩阵的乘积,通常具有一些定义好的性质(如下三角/上三角)。
示例:LU 分解
考虑一个 \(3 \times 3\) 的矩阵 \(A = \begin{bmatrix} 1 & 2 & 2 \\ 4 & 4 & 2 \\ 4 & 6 & 4 \end{bmatrix} .\)
LU 分解是 \({\bf A} = {\bf LU} = \begin{bmatrix} 1 & 0 & 0 \\ 4 & 1 & 0 \\ 4 & 0.5 & 1 \end{bmatrix} \begin{bmatrix} 1 & 2 & 2 \\ 0 & -4 & -6 \\ 0 & 0 & -1 \end{bmatrix}.\)
求解 LU 分解的线性系统
知道矩阵 \({\bf A}\) 的 LU 分解,我们可以通过前向和后向替换的组合来求解线性系统 \({\bf A x} = {\bf b}\)。在方程中,这表示为:
其中我们首先使用前向替换来评估 \({\bf L}^{-1} {\bf b}\),然后使用后向替换来评估 \({\bf x} = {\bf U}^{-1} ({\bf L}^{-1} {\bf b})\)。
一种等效的写法是引入一个新的向量 \({\bf y}\),定义为 \(\bf{y} = {\bf U x}\)。假设矩阵 \(\bf{A}\) 的 LU 分解已知,我们可以求解一般系统
通过解两个三角形系统:
因此,我们将 \({\bf A x} = {\bf b}\) 替换为两个线性系统:\({\bf L y} = {\bf b}\) 和 \({\bf U x} = {\bf y}\)。然后,可以使用前向和后向替换依次求解这两个线性系统。
LU 求解算法的操作次数为 \(O(n²)\),当 \(n \to \infty\) 时。
解决线性系统 \({\bf L U x} = {\bf b}\) 的LU 求解算法代码是:
import numpy as np
def lu_solve(L, U, b):
"""x = lu_solve(L, U, b) is the solution to L U x = b
L must be a lower-triangular matrix
U must be an upper-triangular matrix of the same size as L
b must be a vector of the same leading dimension as L
"""
y = forward_sub(L, b)
x = back_sub(U, y)
return x
LU 分解算法
给定一个矩阵 \({\bf A}\),有许多不同的算法可以找到用于 LU 分解的矩阵 \({\bf L}\) 和 \({\bf U}\)。在这里,我们将使用递归主行列 LU 算法。让我们首先考虑一个简单的情况,即当 \({\bf A}\) 是一个 \(2\times 2\) 矩阵时:
勘误**上面的图实际上是损坏的(我们正在修复它)。它应该是 U11 = A11 和 U12 = A12. *使用类似的思想,当 \({\bf A}\) 是一个 \(n\times n\) 矩阵时,将 \({\bf A}\) 写成块形式:

然后,\({\bf A} = {\bf LU}\) 可以重新写为:
在上述 \(n \times n\) 矩阵 \({\bf A}\) 的块形式中,项 \(a_{11}\) 是一个标量,\(\boldsymbol{a}_{12}\) 是一个 \(1 \times (n-1)\) 行向量,\(\boldsymbol{a}_{12}\) 是一个 \((n-1) \times 1\) 列向量,而 \({\bf A}_{22}\) 是一个 \((n-1) \times (n-1)\) 矩阵。
比较上述块矩阵方程的左右两侧的项,我们注意到:
这四个方程可以重新排列,以求解 \({\bf L}\) 和 \({\bf U}\) 矩阵的分量:
注意:
-
\(\bf{U}\) 的第一行是 \(\bf{A}\) 的第一行。
-
\(\bf{L}\) 的第一列是 \(\frac{\text{矩阵 }\textbf{A} \text{ 的第一列}}{u_{11}}\)。
-
\({\bf L}_{22} {\bf U}_{22}\) 需要另一个分解。
换句话说,上面的前三个方程可以立即计算出来,给出 \({\bf L}\) 和 \({\bf U}\) 的第一行和第一列。然后可以计算最后一个方程的右侧,这将给出 \({\bf A}\) 的 Schur 补 \(S_{22}\)。因此,我们得到方程 \({\bf L}_{22} {\bf U}_{22} = {\bf S}_{22}\),这是一个 \((n-1) \times (n-1)\) 的 LU 分解问题,我们可以递归地解决。
找到 \({\bf A} = {\bf LU}\) 的 \({\bf L}\) 和 \({\bf U}\) 的 递归主行主列 LU 算法 代码如下:
import numpy as np
def lu_decomp(A):
"""(L, U) = lu_decomp(A) is the LU decomposition A = L U
A is any square matrix
L will be a lower-triangular matrix with 1 on the diagonal
U will be an upper-triangular matrix
"""
n = A.shape[0]
# Initialize L and U as zero matrices of the same shape as A
L = np.eye(n) # L is initialized with 1s on the diagonal
U = np.zeros((n, n))
for i in range(n):
# Compute the U matrix (upper triangular)
for j in range(i, n):
U[i, j] = A[i, j] - np.dot(L[i, :i], U[:i, j])
# Compute the L matrix (lower triangular)
for j in range(i + 1, n):
if U[i, i] == 0:
raise ZeroDivisionError("Zero pivot encountered. Cannot factorize.")
L[j, i] = (A[j, i] - np.dot(L[j, :i], U[:i, i])) / U[i, i]
return L, U
除法次数:\((n-1)+(n-2)+\ldots+1=\frac{n(n-1)}{2}\)
乘法次数:\((n-1)²+(n-2)²+\ldots+1²=\frac{n³}{3} - \frac{n²}{2} + \frac{n}{6}\)
减法次数:\((n-1)²+(n-2)²+\ldots+1²=\frac{n³}{3} - \frac{n²}{2} + \frac{n}{6}\)
因此,递归主行主列 LU 分解算法的操作次数为 \(\bf{O(n³)}\),当 \(n \to \infty\) 时。
示例:LU 分解
考虑矩阵 \(\bf{A} = \begin{bmatrix} 2 & 8 & 4 & 1 \\ 1 & 2 & 3 & 3 \\ 1 & 2 & 6 & 2 \\ 1 & 3 & 4 & 2 \end{bmatrix} .\)
我们如何找到这个矩阵的 LU 分解?
答案
注意,我们使用 \(\bf {M}\) 来跟踪需要递归分解的矩阵(例如第一步中的 \(\bf {L_{22}U_{22}}\))。
\(\bf{U}\) 的第一行是 \(\bf{A}\) 的第一行。
\(\bf{L}\) 的第一列是 \(\frac{\text{矩阵 }\textbf{A} \text{ 的第一列}}{u_{11}}\)。
此外,由于 \({\bf L}_{22} {\bf U}_{22} = {\bf A}_{22} - \boldsymbol{a}_{21} (a_{11})^{-1} \boldsymbol{a}_{12}\),在第一步之后我们得到以下结果(注意我们使用张量积运算符 "\(\otimes\)" 来表示两个向量的外积):$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ \textbf{0.5} & 1 & 0 & 0 \ \textbf{0.5} & ? & 1 & 0 \ \textbf{0.5} & ? & ? & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 2 & \textbf{8} & \textbf{4} & \textbf{1} \ 0 & ? & ? & ? \ 0 & 0 & ? & ? \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \textbf{M} = \begin{bmatrix} 2 & 3 & 3 \ 2 & 6 & 2 \ 3 & 4 & 2 \end{bmatrix} - \begin{bmatrix} 0.5 \ 0.5 \ 0.5 \end{bmatrix} \otimes \begin{bmatrix} 8 \ 4 \ 1 \end{bmatrix} = \begin{bmatrix} -2 & 1 & 2.5 \ -2 & 4 & 1.5 \ -1 & 2 & 1.5 \end{bmatrix} $ 类似地,在第二步(递归)中:$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0.5 & 1 & 0 & 0 \ 0.5 & \textbf{1} & 1 & 0 \ 0.5 & \textbf{0.5} & ? & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 2 & 8 & 4 & 1 \ 0 & -2 & \textbf{1} & \textbf{2.5} \ 0 & 0 & ? & ? \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \textbf{M} = \begin{bmatrix} 4 & 1.5 \ 2 & 1.5 \end{bmatrix} - \begin{bmatrix} 1 \ 0.5 \end{bmatrix} \otimes \begin{bmatrix} 1 \ 2.5 \end{bmatrix} = \begin{bmatrix} 3 & -1 \ 1.5 & 0.25 \end{bmatrix} $ 下一步是:$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0.5 & 1 & 0 & 0 \ 0.5 & 1 & 1 & 0 \ 0.5 & 0.5 & \textbf{0.5} & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 2 & 8 & 4 & 1 \ 0 & -2 & 1 & 2.5 \ 0 & 0 & 3 & \textbf{-1} \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \textbf{M} = \begin{bmatrix} 0.25 \end{bmatrix} - \begin{bmatrix} 0.5 \end{bmatrix} \otimes \begin{bmatrix} -1 \end{bmatrix} = \begin{bmatrix} 0.75 \end{bmatrix} $ 因此,最终结果是:$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0.5 & 1 & 0 & 0 \ 0.5 & 1 & 1 & 0 \ 0.5 & 0.5 & 0.5 & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 2 & 8 & 4 & 1 \ 0 & -2 & 1 & 2.5 \ 0 & 0 & 3 & -1 \ 0 & 0 & 0 & 0.75 \end{bmatrix} $
示例:LU 分解失败的矩阵
一个没有 LU 分解的矩阵的例子是
为什么?
答案
LU 分解的第一步是(注意我们使用张量积运算符"\(\otimes\)"来表示两个向量的外积):$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ \textbf{0.5} & 1 & 0 & 0 \ \textbf{0.5} & ? & 1 & 0 \ \textbf{0.5} & ? & ? & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 2 & 8 & 4 & 1 \ 0 & ? & ? & ? \ 0 & 0 & ? & ? \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \bf{L_{22}U_{22}} = \begin{bmatrix} 4 & 3 & 3 \ 2 & 6 & 2 \ 3 & 4 & 2 \end{bmatrix} - \begin{bmatrix} 0.5 \ 0.5 \ 0.5 \end{bmatrix} \otimes \begin{bmatrix} 8 \ 4 \ 1 \end{bmatrix} = \begin{bmatrix} \textbf{0} & 1 & 2.5 \ -2 & 4 & 1.5 \ -1 & 2 & 1.5 \end{bmatrix} $ 下一个更新将导致除以零。LU 分解失败,因此\(\bf A\)没有正常的 LU 分解。
使用 LU 分解求解线性系统
我们可以将上述部分组合起来,生成求解系统\({\bf A x} = {\bf b}\)的算法,其中我们首先计算\({\bf A}\)的 LU 分解,然后使用前向和后向替换来求解\({\bf x}\)。
该算法的性质包括:
-
即使\({\bf A}\)是可逆的,算法也可能失败。
-
随着 n 趋向于无穷大,算法中的操作数是\(\mathcal{O}(n³)\)。
使用 LU 分解的线性求解器代码是:
import numpy as np
def linear_solve_without_pivoting(A, b):
"""x = linear_solve_without_pivoting(A, b) is the solution to A x = b (computed without pivoting)
A is any matrix
b is a vector of the same leading dimension as A
x will be a vector of the same leading dimension as A
"""
(L, U) = lu_decomp(A)
x = lu_solve(L, U, b)
return x
旋转
当矩阵\({\bf A}\)的左上角元素为零或与其他元素相比非常小的时候,LU 分解可能会失败。旋转是一种通过重新排列\({\bf A}\)的行和/或列,将较大的元素放置在左上角位置来减轻这种问题的策略。
有许多不同的旋转算法。其中最常见的是完全旋转、部分旋转和缩放部分旋转。我们只将详细讨论部分旋转。
- 部分旋转只重新排列\({\bf A}\)的行,并保持列不变。

- 完全旋转重新排列行和列。

- 缩放部分旋转在不实际重新排列列的情况下近似完全旋转。
部分旋转 LU 分解
\(n \times n\)矩阵\({\bf A}\)的部分旋转 LU 分解(LUP)是矩阵\({\bf L}\)、\({\bf U}\)和\({\bf P}\)的三元组,使得:
-
${\bf P A} = {\bf LU} $
-
\({\bf L}\)是一个\(n \times n\)的下三角矩阵,所有对角线元素都等于 1。
-
\({\bf U}\)是一个\(n \times n\)的上三角矩阵。
-
\({\bf P}\)是一个\(n \times n\)的置换矩阵。
LUP 分解的性质包括:
-
置换矩阵 \({\bf P}\) 作用于 \({\bf A}\) 的行。这试图将大项放在 \({\bf A}\) 的左上角位置以及递归中的每个子矩阵中,以避免需要除以小或零元素。
-
对于矩阵 \({\bf A}\),LUP 分解总是存在的。
-
矩阵 \({\bf A}\) 的 LUP 分解不是唯一的。
-
LUP 分解提供了一种比没有选主元的 LU 分解更鲁棒的求解线性系统的方法,并且其成本大致相同。
带部分选主元的 LU 分解可以对任何矩阵 A 完成:假设你处于第 k 阶段,并且在第 k 列的对角线以下没有非零项。在这种情况下,你无法再进行其他操作,因此算法在 U 的对角线位置留下一个零。请注意,矩阵 U 是奇异的,矩阵 A 也是奇异的。使用 U 进行后续的回代将失败,但 LU 分解本身仍然完成。
解决 LUP 分解线性系统
知道矩阵 \({\bf A}\) 的 LUP 分解允许我们通过首先应用 \({\bf P}\),然后使用 LU 求解器来解决线性系统 \({\bf A x} = {\bf b}\)。在方程中,我们首先取 \({\bf A x} = {\bf b}\),并将两边乘以 \({\bf P}\),得到
解决线性系统 \({\bf L U x} = {\bf P b}\) 的 LUP 解算法 代码如下:
import numpy as np
def lup_solve(L, U, P, b):
"""x = lup_solve(L, U, P, b) is the solution to L U x = P b
L must be a lower-triangular matrix
U must be an upper-triangular matrix of the same shape as L
P must be a permutation matrix of the same shape as L
b must be a vector of the same leading dimension as L
"""
z = np.dot(P, b)
x = lu_solve(L, U, z)
return x
LUP 解算法的操作次数为 \(\mathcal{O}(n²)\),当 \(n \to \infty\) 时。
LUP 分解算法
正如存在不同的 LU 分解算法一样,也存在不同的 LUP 分解算法。这里我们使用 递归主行主列 LUP 算法。
此算法是寻找 \({\bf L}\),\({\bf U}\) 和 \({\bf P}\) 的递归方法,使得 \({\bf P A} = {\bf L U}\)。它包括以下步骤。
-
首先选择 \(i\),使得 \({\bf A}\) 的第 \(i\) 行具有最大的绝对第一个元素。也就是说,对于所有 \(j\),\(\vert A_{i1}\vert \ge \vert A_{j1}\vert\)。设 \({\bf P}_1\) 为将第 \(i\) 行旋转(移动)到第一行,并保持所有其他行顺序的置换矩阵。我们可以明确写出 \({\bf P}_1\) 为
\[{\bf P}_1 = \begin{bmatrix} 0_{1(i-1)} & 1 & 0_{1(n-i)} \\ I_{(i-1)(i-1)} & 0 & 0_{(i-1)(n-i)} \\ 0_{(n-i)(i-1)} & 0 & I_{(n-i)(n-i)} \end{bmatrix} = \begin{bmatrix} 0 & \ldots & 0 & 1 & 0 & \ldots & 0 \\ 1 & \ldots & 0 & 0 & 0 & \ldots & 0 \\ \vdots & \ddots & \vdots & \vdots & \vdots & \ldots & 0 \\ 0 & \ldots & 1 & 0 & 0 & \ldots & 0 \\ 0 & \ldots & 0 & 0 & 1 & \ldots & 0 \\ \vdots & \ddots & \vdots & \vdots & \vdots & \ldots & 0 \\ 0 & \ldots & 0 & 0 & 0 & \ldots & 1 \end{bmatrix}. \] -
用 \(\bar{ {\bf A} }\) 表示选主元的 \({\bf A}\) 矩阵,因此 \(\bar{ {\bf A} } = {\bf P}_1 {\bf A}\)。
-
设 \({\bf P}_2\) 为一个置换矩阵,它保持第一行不变,但交换所有其他行。我们可以将 \({\bf P}_2\) 写成 \({\bf P}_2 = \begin{bmatrix} 1 & \boldsymbol{0} \\ \boldsymbol{0} & P_{22} \end{bmatrix},\) 其中 \({\bf P}_{22}\) 是一个 \((n-1) \times (n-1)\) 的置换矩阵。
-
将(未知的)完整置换矩阵 \({\bf P}\) 分解为 \({\bf P}_2\) 和 \({\bf P}_1\) 的乘积,即 \({\bf P} = {\bf P}_2 {\bf P}_1\)。这意味着 \({\bf P} A = {\bf P}_2 {\bf P}_1 A = {\bf P}_2 \bar{ {\bf A} }\),这首先将 \({\bf A}\) 的第 \(i\) 行移到顶部,然后交换剩余的行。这是一个完全一般的置换矩阵 \({\bf P}\),但这种分解对于实现递归算法至关重要。
-
使用因式分解 \({\bf P} = {\bf P}_2 {\bf P}_1\),现在将 LUP 分解写成块形式
\[\begin{aligned} {\bf P A} &= {\bf L U} \\ {\bf P_2} \bar{ {\bf A} } &= {\bf L U} \\ \begin{bmatrix} 1 & \boldsymbol{0} \\ \boldsymbol{0} & {\bf P}_{22} \end{bmatrix} \begin{bmatrix} \bar{a}_{11} & \bar{\boldsymbol{a}}_{12} \\ \bar{\boldsymbol{a}}_{21} & \bar{ {\bf A} }_{22} \end{bmatrix} &= \begin{bmatrix} 1 & \boldsymbol{0} \\ \boldsymbol{\ell}_{21} & {\bf L}_{22} \end{bmatrix} \begin{bmatrix} u_{11} & \boldsymbol{u}_{12} \\ \boldsymbol{0} & {\bf U}_{22} \end{bmatrix} \\ \begin{bmatrix} \bar{a}_{11} & \bar{\boldsymbol{a}}_{12} \\ {\bf P}_{22} \bar{\boldsymbol{a}}_{21} & {\bf P}_{22} \bar{ {\bf A} }_{22} \end{bmatrix} &= \begin{bmatrix} u_{11} & \boldsymbol{u}_{12} \\ u_{11} \boldsymbol{\ell}_{21} & (\boldsymbol{\ell}_{21} \boldsymbol{u}_{12} + {\bf L}_{22} {\bf U}_{22}) \end{bmatrix} \end{aligned} \] -
将上述矩阵中的对应项相等,得到方程
\[\begin{aligned} \bar{a}_{11} &= u_{11} \\ \bar{\boldsymbol{a}}_{12} &= \boldsymbol{u}_{12} \\ {\bf P}_{22} \bar{\boldsymbol{a}}_{21} &= u_{11} \boldsymbol{\ell}_{21} \\ {\bf P}_{22} \bar{A}_{22} &= \boldsymbol{\ell}_{21} \boldsymbol{u}_{12} + {\bf L}_{22} {\bf U}_{22}. \end{aligned} \] -
将上述前三个方程代入最后一个方程并重新排列得到
\[{\bf P}_{22} \underbrace{\Bigl(\bar{A}_{22} - \bar{\boldsymbol{a}}_{21} (\bar{a}_{11})^{-1} \bar{\boldsymbol{a}}_{12}\Bigr)}_{\text{Schur complement } {\bf S}_{22}} = {\bf L}_{22} {\bf U}_{22}. \] -
递归求解 \(S_{22}\) 的 LUP 分解,得到满足上述方程的 \({\bf L}_{22}\),\({\bf U}_{22}\) 和 \({\bf P}_{22}\)。
-
使用上述方程求解 \({\bf L}\) 和 \({\bf U}\) 的第一行和列,得到
\[\begin{aligned} u_{11} &= \bar{a}_{11} \\ \boldsymbol{u}_{12} &= \bar{\boldsymbol{a}}_{12} \\ \boldsymbol{\ell}_{21} &= \frac{1}{\bar{a}_{11}} {\bf P}_{22} \bar{\boldsymbol{a}}_{21}. \end{aligned} \] -
最后,从组成部分重建完整的矩阵 \({\bf L}\),\({\bf U}\) 和 \({\bf P}\)。
在代码中,用于找到 \({\bf A}\) 的 LU 分解的带部分主元选择的递归主行主列 LUP 算法为:
import numpy as np
def lup_decomp(A):
"""(L, U, P) = lup_decomp(A) is the LUP decomposition P A = L U
A is any matrix
L will be a lower-triangular matrix with 1 on the diagonal, the same shape as A
U will be an upper-triangular matrix, the same shape as A
P will be a permutation matrix, the same shape as A
"""
n = A.shape[0]
if n == 1:
L = np.array([[1]])
U = A.copy()
P = np.array([[1]])
return (L, U, P)
i = np.argmax(A[:,0])
A_bar = np.vstack([A[i,:], A[:i,:], A[(i+1):,:]])
A_bar11 = A_bar[0,0]
A_bar12 = A_bar[0,1:]
A_bar21 = A_bar[1:,0]
A_bar22 = A_bar[1:,1:]
S22 = A_bar22 - np.dot(A_bar21, A_bar12) / A_bar11
(L22, U22, P22) = lup_decomp(S22)
L11 = 1
U11 = A_bar11
L12 = np.zeros(n-1)
U12 = A_bar12.copy()
L21 = np.dot(P22, A_bar21) / A_bar11
U21 = np.zeros(n-1)
L = np.block([[L11, L12], [L21, L22]])
U = np.block([[U11, U12], [U21, U22]])
P = np.block([
[np.zeros((1, i-1)), 1, np.zeros((1, n-i))],
[P22[:,:(i-1)], np.zeros((n-1, 1)), P22[:,i:]]
])
return (L, U, P)
递归主行主列 LUP 分解算法的特性包括:
-
当 \(n \to \infty\) 时,该算法的计算复杂度(操作次数)为 \(\mathcal{O}(n³)\)。
-
代码中计算 \({\bf P}\) 的最后一步并不是通过构造和乘以 \({\bf P}_2\) 和 \({\bf P}_1\) 来实现的。这是因为这将是一个 \(\mathcal{O}(n³)\) 的步骤,使得整个算法变为 \(\mathcal{O}(n⁴)\)。相反,我们利用 \({\bf P}_2\) 和 \({\bf P}_1\) 的特殊结构,以 \(\mathcal{O}(n²)\) 的工作量来计算 \({\bf P}\)。
使用 LUP 分解求解一般线性方程组
正如普通的 LU 分解一样,我们可以使用 LUP 分解来解决线性方程组 \({\bf A x }= {\bf b}\)。这是使用 LUP 分解的线性求解器算法。
该算法的特性包括:
-
该算法可能会失败。特别是如果 \({\bf A}\) 是奇异的(或在有限精度下是奇异的),U 的对角线上将会有一个零。
-
由于 LU 分解有 \(\mathcal{O}(n³)\) 次操作,而求解 \(Ly = b\) 和 \(Ux = y\) 都有 \(\mathcal{O}(n²)\) 次操作,因此当 \(n \to \infty\) 时,该算法的总操作次数为 \(\bf{\mathcal{O}(n³)}\)。
-
我们将分解步骤与实际求解步骤解耦,因为在某些工程应用中,在求解多个线性方程组时,可能可以重用同一矩阵的 LU 分解。
使用 LUP 分解的线性求解器的代码为:
import numpy as np
def linear_solve(A, b):
"""x = linear_solve(A, b) is the solution to A x = b (computed with partial pivoting)
A is any matrix
b is a vector of the same leading dimension as A
x will be a vector of the same leading dimension as A
"""
(L, U, P) = lup_decomp(A)
x = lup_solve(L, U, P, b)
return x
示例:LUP 分解
考虑矩阵 \(\bf{A} = \begin{bmatrix} 2 & 1 & 1 & 0 \\ 4 & 3 & 3 & 1 \\ 8 & 7 & 9 & 5 \\ 6 & 7 & 9 & 8 \end{bmatrix} .\)
我们如何找到这个矩阵的 LUP 分解?
答案
注意,我们使用 \({\bf {\overline{M}}}\) 来跟踪需要递归分解的矩阵(例如第一步中的 \(\bf L_{22} U_{22}\)),并且使用张量积运算符 "\(\otimes\)" 来表示两个向量的外积。在第一步中:$ \bf{P\overline{M}} = \begin{bmatrix} 0 & 0 & 1 & 0 \ 0 & 1 & 0 & 0 \ 1 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 2 & 1 & 1 & 0 \ 4 & 3 & 3 & 1 \ 8 & 7 & 9 & 5 \ 6 & 7 & 9 & 8 \end{bmatrix} = \begin{bmatrix} 8 & 7 & 9 & 5 \ 4 & 3 & 3 & 1 \ 2 & 1 & 0 & 0 \ 6 & 7 & 9 & 8 \end{bmatrix} $ $ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ \textbf{0.5} & 1 & 0 & 0 \ \textbf{0.25} & ? & 1 & 0 \ \textbf{0.75} & ? & ? & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 8 & \textbf{7} & \textbf{9} & \textbf{5} \ 0 & ? & ? & ? \ 0 & 0 & ? & ? \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \bf{\overline{M}} = \begin{bmatrix} 3 & 3 & 1 \ 1 & 0 & 0 \ 7 & 9 & 8 \end{bmatrix} - \begin{bmatrix} 0.5 \ 0.25 \ 0.75 \end{bmatrix} \otimes \begin{bmatrix} 7 \ 9 \ 5 \end{bmatrix} = \begin{bmatrix} -0.5 & -1.5 & -1.5 \ -0.75 & -1.25 & -1.25 \ 1.75 & 2.25 & 4.25 \end{bmatrix} $ 类似地,在第二步(递归)中:$ \bf{P\overline{M}} = \begin{bmatrix} 0 & 0 & 1 \ 0 & 1 & 0 \ 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} -0.5 & -1.5 & -1.5 \ -0.75 & -1.25 & -1.25 \ 1.75 & 2.25 & 4.25 \end{bmatrix} = \begin{bmatrix} 1.75 & 2.25 & 4.25 \ -0.75 & -1.25 & -1.25 \ -0.5 & -1.5 & -1.5 \end{bmatrix} $ $ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ \textbf{0.75} & 1 & 0 & 0 \ 0.25 & \textbf{-0.428} & 1 & 0 \ \textbf{0.5} & \textbf{-0.285} & ? & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 8 & 7 & 9 & 5 \ 0 & \textbf{1.75} & \textbf{2.25} & \textbf{4.25} \ 0 & 0 & ? & ? \ 0 & 0 & 0 & ? \end{bmatrix} $ $ \bf{\overline{M}} = \begin{bmatrix} -1.25 & -1.25 \ -1.5 & -1.5 \end{bmatrix} - \begin{bmatrix} -0.428 \ -0.285 \end{bmatrix} \otimes \begin{bmatrix} 2.25 \ 4.25 \end{bmatrix} = \begin{bmatrix} -0.287 & 0.569 \ -0.8587 & -0.2887 \end{bmatrix} $ 下一步是:$ \bf{P\overline{M}} = \begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix} \begin{bmatrix} -0.287 & 0.569 \ -0.8587 & -0.2887 \end{bmatrix} = \begin{bmatrix} -0.8587 & -0.2887 \ -0.287 & 0.569 \end{bmatrix} $ $ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0.75 & 1 & 0 & 0 \ \textbf{0.5} & \textbf{-0.285} & 1 & 0 \ \textbf{0.25} & \textbf{-0.428} & \textbf{0.334} & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 8 & 7 & 9 & 5 \ 0 & 1.75 & 2.25 & 4.25 \ 0 & 0 & \textbf{-0.86} & \textbf{-0.29} \ 0 & 0 & 0 & ? \end{bmatrix}; \hspace{5mm} \bf{\overline{M}} = \begin{bmatrix} 0.569 \end{bmatrix} - \begin{bmatrix} 0.334 \end{bmatrix} \otimes \begin{bmatrix} -0.29 \end{bmatrix} = \begin{bmatrix} 0.67 \end{bmatrix} $ 因此,最终结果是:$ \textbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \ 0.75 & 1 & 0 & 0 \ 0.5 & -0.285 & 1 & 0 \ 0.25 & -0.428 & 0.334 & 1 \end{bmatrix}; \hspace{5mm} \textbf{U} = \begin{bmatrix} 8 & 7 & 9 & 5 \ 0 & 1.75 & 2.25 & 4.25 \ 0 & 0 & -0.86 & -0.29 \ 0 & 0 & 0 & 0.67 \end{bmatrix}; \hspace{5mm} \textbf{P} = \begin{bmatrix} 0 & 0 & 1 & 0 \ 0 & 0 & 0 & 1 \ 0 & 1 & 0 & 0 \ 1 & 0 & 0 & 0 \end{bmatrix} $
示例:LUP 分解成功但 LU 分解失败的矩阵
考虑一个没有 LU 分解的矩阵:
我们如何找到这个矩阵的 LUP 分解?
答案
要找到 \(\bf A\) 的 LUP 分解,我们首先写出置换矩阵 \({\bf P}\),将第二行移到顶部,使得左上角的元素具有最大的可能幅度。这给出 $ \overbrace{\begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix}}^{P} \overbrace{\begin{bmatrix} 0 & 1 \ 2 & 1 \end{bmatrix}}^{A} = \overbrace{\begin{bmatrix} 2 & 1 \ 0 & 1 \end{bmatrix}}^{\bar{A}} = \overbrace{\begin{bmatrix} 1 & 0 \ 0 & 1 \end{bmatrix}}^{L} \overbrace{\begin{bmatrix} 2 & 1 \ 0 & 1 \end{bmatrix}}^{U}. $
复习问题
-
给定分解 \({\bf P A} = {\bf LU}\),你将如何解方程 \({\bf A}\mathbf{x} = \mathbf{b}\)?
-
理解解三角系统的过程。解一个示例三角系统。
-
识别和理解实现前向替换、后向替换和 LU 分解的 Python 代码。
-
LU 分解何时存在?
-
LUP 分解何时存在?
-
\({\bf P}\),\({\bf L}\) 和 \({\bf U}\) 有哪些特殊性质?
-
我们能否找到一个奇异矩阵的 LUP 分解?
-
如果我们尝试用奇异矩阵 \({\bf A}\) 解方程 \({\bf A}\mathbf{x} = \mathbf{b}\),会发生什么?
-
通过手工计算一个小矩阵的 LU 分解。
-
为什么在解线性系统时使用主元?
-
我们如何选择主元元素?
-
给定的置换矩阵乘以另一个矩阵时有什么影响?
-
矩阵-矩阵乘法的成本是多少?
-
计算 LU 或 LUP 分解的成本是多少?
-
前向替换或后向替换的成本是多少?
-
解一般矩阵 \({\bf A}\mathbf{x} = \mathbf{b}\) 的成本是多少?
-
解三角矩阵 \({\bf A}\mathbf{x} = \mathbf{b}\) 的成本是多少?
-
使用相同的矩阵 \({\bf A}\) 和几个右端向量 \(\mathbf{b}_i\) 解 \({\bf A}\mathbf{x} = \mathbf{b_i}\) 的成本是多少?
-
给定一个时间复杂度为 \(\mathcal{O}(n^k)\) 的过程,如果我们加倍输入大小(即加倍 \(n\)),运行时间会发生什么变化?如果我们三倍输入大小呢?
更新日志
-
2024 年 10 月 2 日:Dev Singh (dsingh14) — 修复 lu_decomp
-
2024 年 9 月 30 日:Kaiyao Ke (kaiyaok2) — 修复小错误
-
2024 年 2 月 13 日:Kaiyao Ke (kaiyaok2) — 将笔记与幻灯片对齐,添加示例并重构现有笔记
查看剩余条目
+ 2023 年 10 月 20 日:Yuxuan Chen (yuxuan19) — 更新 lu_decomp() 代码
+ 2018 年 2 月 28 日:Erin Carrier (ecarrie2) — 修复 ludecomp() 代码中的错误
+ 2018 年 2 月 22 日:Erin Carrier (ecarrie2) — 更新使用 LUP 解决属性
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 删除演示链接
+ 2017 年 11 月 2 日:Arun Lakshmanan (lakshma2) — 在 lup_solve() 中进行小修,添加变更日志
+ 2017 年 11 月 2 日:John Doherty (jjdoher2) — 修复回代中的错别字
+ 2017 年 10 月 25 日:Nathan Bowman (nlbowma2) — 添加复习问题
+ 2017 年 10 月 23 日:Erin Carrier (ecarrie2) — 修复链接
+ 2017 年 10 月 20 日:Matthew West (mwest) — 在 back_sub() 中进行小修
+ 2017 年 10 月 19 日:Nathan Bowman (nlbowma2) — 小修 LUP 的存在性
+ 2017 年 10 月 17 日:Erin Carrier (ecarrie2) — 修复
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 更新链接
+ 2017 年 10 月 16 日:Matthew West (mwest) — 完成初稿
作者
- CS 357 课程工作人员*
稀疏矩阵
稠密矩阵
稠密矩阵存储所有值,包括零。因此,一个 \(m \times n\) 的矩阵必须存储 \(O(m \times n)\) 个项。例如:
为了存储矩阵,所有组件通常以行主序保存。对于上面给出的 \(\mathbf{A}\),我们会存储:
矩阵的维度是单独存储的:
稀疏矩阵
一些类型的矩阵包含太多的零,存储所有这些零项是浪费的。稀疏矩阵是一种非零项很少的矩阵。
一个 \(m \times n\) 的矩阵如果它有 \(O(min(m, n))\) 个非零项,则称为稀疏矩阵。
目标
稀疏矩阵旨在以高效的方式存储大型矩阵,而不存储许多零,这允许进行更经济的计算。它还节省了存储空间,这可以减少系统上的内存开销。
添加两个稠密矩阵 \(\mathbf{P}\) 和 \(\mathbf{Q}\) 所需的操作数是 \(O(n(\mathbf{P}) + n(\mathbf{Q}))\),其中 \((n(\mathbf{X}))\) 是 \(\mathbf{X}\) 中的元素数量。
添加两个稀疏矩阵 \(\mathbf{P}\) 和 \(\mathbf{Q}\) 所需的操作数是 \(O(nnz(\mathbf{P}) + nnz(\mathbf{Q}))\),其中 \((nnz(\mathbf{X}))\) 是 \(\mathbf{X}\) 中非零元素的数量。
存储解决方案
存储稀疏矩阵的方法有很多,如坐标(COO)、压缩稀疏行(CSR)、块稀疏行(BSR)、键字典(DOK)等。
我们将重点关注坐标和压缩稀疏行。
让我们探索存储以下示例的方法:
坐标格式(COO)
COO 存储行索引、列索引和相应的非零数据值的数组,顺序可以是任意的。这种格式提供了快速构建稀疏矩阵和转换为不同稀疏格式的方法。对于 \({\bf A}\) 的 COO 格式是:
\(\textrm{row}\) 和 \(\textrm{col}\) 是 \(nnz\) 个整数的数组。
\(\textrm{data}\) 是原始矩阵数据类型的 \(nnz\) 数组,在这种情况下是双精度浮点数。
如何解释:\(\textrm{data}\),\(\textrm{row}\),\(\textrm{col}\) 的前几个条目分别是 12.0,4,4,这意味着矩阵的位置 (4, 4) 处有 12.0;第二个条目是 9.0,2,4,所以 (2, 4) 处有 9.0。
COO 矩阵存储 \(3 \times nnz\) 个元素。这种方法可以排序,因为行、列和数据数组中的每个索引描述的是相同的元素。
在 Python 中,可以使用 scipy.sparse 库将此矩阵转换为 COO 格式。
import scipy.sparse as sparse
A = [[1., 0., 0., 2., 0.],
[ 3., 4., 0., 5., 0.],
[ 6., 0., 7., 8., 9.],
[ 0., 0., 10., 11., 0.],
[ 0., 0., 0., 0., 12.]]
COO = sparse.coo_matrix(A)
data = COO.data
row = COO.row
col = COO.col
您也可以使用 scipy.sparse 库在 Python 中将 COO 格式的稀疏矩阵重新创建为稠密或 CSR 矩阵。
import scipy.sparse as sparse
data = [12.0, 9.0, 7.0, 5.0, 1.0, 2.0, 11.0, 3.0, 6.0, 4.0, 8.0, 10.0]
row = [4, 2, 2, 1, 0, 0, 3, 1, 2, 1, 2, 3]
col = [4, 4, 2, 3, 0, 3, 3, 0, 0, 1, 3, 2]
COO = sparse.coo_matrix((data, (row, col)))
A = COO.todense()
CSR = COO.tocsr()
压缩稀疏行 (CSR)
CSR,也常称为耶鲁格式,编码行偏移、列索引和相应的非零数据值。行偏移由以下递归关系定义(从 \(\textrm{rowptr}[0] = 0\) 开始):
其中 \(\mathrm{nnz}(\textrm{row}_k)\) 是第 \(k\) 行中非零元素的数量。注意,\(\textrm{rowptr}\) 的长度是 \(n_{rows} + 1\),其中 \(\textrm{rowptr}\) 的最后一个元素是 \(A\) 中的非零元素数量。对于 CSR 格式的 \({\bf A}\):
\(\textrm{rowptr}\) 包含行偏移(\(m + 1\) 个整数的数组)。
\(\textrm{col}\) 包含列索引(\(nnz\) 个整数的数组)。
\(\textrm{data}\) 包含非零元素(\(nnz\) 个数据值类型的数组,在这种情况下是双精度浮点数)。
如何解释:\(\textrm{rowptr}\) 的前两个条目给出了第一行的元素。\(\textrm{data}\) 和 \(\textrm{col}\) 的区间 [0, 2) 对应两个 (data, column) 对:$ (1.0, 0) $ 和 $ (2.0, 3) \(,意味着第一行在列 0 处有 1.0,在列 3 处有 2.0。\)\textrm{rowptr}$ 的第二个和第三个条目告诉我们 \(\textrm{data}\) 和 \(\textrm{col}\) 的 [2, 5) 区间对应第二行。三个对 \((3.0, 0)\),\((4.0, 1)\),\((5.0, 3)\) 意味着在第二行中,列 0 处有 3.0,列 1 处有 4.0,列 3 处有 5.0。
CSR 矩阵存储 \(2 \times nnz + m + 1\) 个元素。它还提供了在稀疏矩阵之间进行快速算术运算和快速矩阵向量积的功能。
在 Python 中,可以使用 scipy.sparse 库将此矩阵转换为 CSR 格式。
import scipy.sparse as sparse
A = [[1., 0., 0., 2., 0.],
[ 3., 4., 0., 5., 0.],
[ 6., 0., 7., 8., 9.],
[ 0., 0., 10., 11., 0.],
[ 0., 0., 0., 0., 12.]]
CSR = sparse.csr_matrix(A)
data = CSR.data
col = CSR.indices
rowptr = CSR.indptr
您也可以使用 scipy.sparse 库在 Python 中将 CSR 格式的稀疏矩阵重新创建为稠密或 COO 矩阵。
data = [ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]
col = [ 0, 3, 0, 1, 3, 0, 2, 3, 4, 2, 3, 4]
rowptr = [ 0, 2, 5, 9, 11, 12]
CSR = sparse.csr_matrix((data, col, rowptr))
A = CSR.todense()
COO = CSR.tocoo()
CSR 矩阵向量积算法
以下代码片段执行方阵的 CSR 矩阵向量积:
import numpy as np
def csr_mat_vec(A, x):
Ax = np.zeros_like(x)
for i in range(x.shape[0]):
for k in range(A.rowptr[i], A.rowptr[i+1]):
Ax[i] += A.data[k]*x[A.col[k]]
return Ax
复习问题
-
矩阵稀疏是什么意思?
-
在决定如何存储稀疏矩阵时,您可能考虑哪些因素?(为什么您会选择一种格式而不是另一种格式来存储矩阵?)
-
给定一个稀疏矩阵,将其转换为 CSR 格式。
-
给定一个稀疏矩阵,将其转换为 COO 格式。
-
对于一个给定的矩阵,存储它需要多少字节的 CSR 格式?
-
对于一个给定的矩阵,存储它需要多少字节的 COO 格式?
更新日志
-
2025 年 10 月 28 日:Dev Singh (dsingh14) — 修复了密集矩阵示例
-
2024 年 10 月 31 日:Kaiyao Ke (kaiyaok2) — 修复了小错误
-
2024 年 2 月 14 日:Kriti Chandak (kritic3) — 添加了幻灯片信息和额外的示例
查看剩余条目
+ 2022 年 3 月 6 日:Victor Zhao (chenyan4) — 添加了如何解释 COO 和 CSR 的说明
+ 2020 年 3 月 1 日:Peter Sentz (sentz2) — 从之前的参考页面中提取了材料
作者
- CS 357 课程工作人员
条件数
学习目标
-
计算条件数
-
量化高条件数的影响
数值实验
输入存在不确定性:
-
由于有限精度表示引起的错误
-
采样误差
一旦你选择了你的数值方法,你应该期望在输出中看到多少误差?
你的方法对输入中的误差(扰动)敏感吗?
线性系统解的敏感性和误差界限
动机
假设我们从非奇异线性方程组 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 开始。如果我们通过一个小量 \(\Delta \boldsymbol{b}\) 改变右侧向量 \(\boldsymbol{b}\)(输入),解 \(\boldsymbol{x}\)(输出)将改变多少,即 \(\Delta \boldsymbol{x}\) 有多大?
让我们探索这个问题!
推导
设 \(\boldsymbol{x}\) 是 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的解,\(\hat{\boldsymbol{x}}\) 是扰动问题 \({\bf A} \hat{\boldsymbol{x}} = \boldsymbol{b} + \Delta \boldsymbol{b}\) 的解。
此外,设 \(\Delta \boldsymbol{x} = \hat{\boldsymbol{x}} - \boldsymbol{x}\) 为输出中的绝对误差。
然后,我们有 \({\bf A} \boldsymbol{x} + {\bf A} \Delta \boldsymbol{x} = \boldsymbol{b} + \Delta \boldsymbol{b},\) 因此 \({\bf A} \Delta \boldsymbol{x} = \Delta \boldsymbol{b}.\)
使用上述方程,我们将看到输出中的相对误差 \(\left(\frac{\|\Delta \boldsymbol{x}\|}{\|\boldsymbol{x}\|}\right)\) 与输入中的相对误差 \(\left(\frac{\|\Delta \boldsymbol{b}\|}{\|\boldsymbol{b}\|}\right)\) 之间的关系:
其中我们使用了 \(\|{\bf A}\boldsymbol{x}\| \le \|{\bf A}\| \|\boldsymbol{x}\|, \forall \boldsymbol{x}.\)
矩阵扰动和误差界限
然后
我们也可以通过一个小量 \(\boldsymbol{E}\) 对矩阵 \(\boldsymbol{A}\)(输入)进行扰动,使得
以类似的方式获得:
因此,如果我们知道输入的相对误差,那么我们可以使用系统的条件数来获得我们计算解(输出)的相对误差的上界。
示例
给出一个条件非常好的矩阵的例子(即,具有适合计算的好的条件数)。选择矩阵可能的最优条件数?
答案
\(\bf D\)
矩阵 \({\bf A}\) 的条件数不能小于 1,较小的条件数将最小化输出 \(\left(\frac{\|\Delta \boldsymbol{x}\|}{\|\boldsymbol{x}\|}\right)\) 的相对误差。由于我们希望最小化计算误差,选择 $ \text{D} $ 是正确答案。
条件数
条件数定义
条件数:衡量求解线性方程组对输入变化的敏感度的度量。
一个平方非奇异矩阵 \({\bf A}\) 的 条件数 定义为 \(\text{cond}({\bf A}) = \kappa({\bf A}) = \|{\bf A}\| \|{\bf A}^{-1}\|\)。这也是与求解线性系统 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 相关的条件数。具有大条件数的矩阵被称为 病态的,而具有小条件的矩阵被称为 良态的。
单位矩阵是良态的。我们通过以下方式证明这一点:
假设 \(\|{\bf A}\|\) 的逆存在,\(\text{cond}({\bf A}) = \|{\bf A}\| \|{\bf A}^{-1}\| \geq \|{\bf A}{\bf A}^{-1}\| = \|{\bf I}\| = 1.\)
这是可能的最小条件数。小的条件数对应于小的误差放大。记住,小的条件数是好的!
如果 \({\bf A}\) 是奇异的 (\({\bf A}^{-1}\) 不存在),我们可以按照惯例定义 \(\text{cond}({\bf A}) = \infty\)。
诱导矩阵范数
回想一下,诱导矩阵范数由以下给出:
条件数可以用任何 \(p\)-范数来衡量,因此为了精确起见,我们通常指定所使用的范数,即 \(\text{cond}_2\),\(\text{cond}_1\),\(\text{cond}_{\infty}\)。
对于 1-范数,我们取矩阵 \(\boldsymbol{A}\) 的最大绝对列和。
对于 \(\infty\)-范数,我们取矩阵 \(\boldsymbol{A}\) 的最大绝对行和。
对于 2-范数,\(\sigma_k\) 是矩阵 \(\boldsymbol{A}\) 的奇异值。
正交矩阵的条件数
正交矩阵 \(\boldsymbol{A}\) 的 2-范数条件数是多少?
因此,这意味着正交矩阵具有最优的条件数。
关于条件数需要记住的事情
-
对于任何矩阵 \({\bf A}\),\(\text{cond}({\bf A}) \geq 1.\)
-
对于单位矩阵 \({\bf I}\),\(\text{cond}({\bf I}) = 1.\)
-
对于任何矩阵 \({\bf A}\) 和一个非零标量 \(\gamma\),\(\text{cond}(\gamma {\bf A}) = \text{cond}({\bf A}).\)
-
对于任何对角矩阵 \({\bf D}\),\(\text{cond}({\bf D})\) = \(\frac{\text{max}\mid d_{i} \mid}{\text{min}\mid d_{i} \mid}.\)
-
条件数是衡量矩阵接近奇异性程度的一个指标:条件数大的矩阵几乎奇异,而条件数接近 1 的矩阵远非奇异。
-
矩阵的行列式并不是检查矩阵是否接近奇异性好的指标。
示例
对角矩阵的 2-范数条件数是多少?
答案
\(\bf D\)
如上所述,对于任何对角矩阵 \({\bf D}\),$\text{cond}({\bf D}) $ = \(\frac{\text{max}\mid d_{i} \mid}{\text{min}\mid d_{i} \mid}.\) 因此,答案是 $ 100 / 0.5 = 200. $
另一种处理这个问题的方法是求对角矩阵 \({\bf A}\) 的逆:
$ \mathbf{A^{-1}} = \begin{bmatrix} 1/100 & 0 & 0 \ 0 & 1/13 & 0 \ 0 & 0 & 2 \end{bmatrix}? $
$ \begin{align} \text{cond}({\bf A}) = |{\bf A}|_2 |{\bf A}^{-1}|_2 = 100 * 2 = 200 \end{align} $
残差与误差
近似解 \(\hat{\boldsymbol{x}}\) 对于线性系统 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的残差向量 \(\boldsymbol{r}\) 定义为 \(\boldsymbol{r} = \boldsymbol{b} - {\bf A} \hat{\boldsymbol{x}}\). 由于 \({\bf A} \hat{\boldsymbol{x}} = \boldsymbol{b} + \Delta \boldsymbol{b}\),我们有
因此,方程(1)也可以写成
如果我们定义相对残差为 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{b}\|}\),我们可以看到,只有当 \({\bf A}\) 是良态的(\(\text{cond}({\bf A})\) 小)时,小的相对残差才意味着近似解中的小的相对误差。
此外,重要的是要注意相对残差和相对误差之间的区别。相对残差 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{b}\|}\) 告诉我们近似解 \(\hat{\boldsymbol{x}}\) 满足线性系统 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的程度。相对误差 \(\frac{\|\Delta \boldsymbol{x}\|}{\|\boldsymbol{x}\|}\) 告诉我们近似解 \(\hat{\boldsymbol{x}}\) 与精确解 \(\boldsymbol{x}\) 的接近程度。记住,我们不知道精确解 \(\boldsymbol{x}\),这就是为什么我们开始使用残差向量 \(\boldsymbol{r}\) 的原因。
示例
假设我们有一个 \({\boldsymbol{x}}\) 是 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的解,\(\hat {\boldsymbol{x}}\) 是 \({\bf A} \hat{\boldsymbol{x}} = \boldsymbol{b} + \Delta \boldsymbol{b}\) 的解。我们定义 \({\bf r} = {\bf A} \hat{\boldsymbol{x}} - \boldsymbol{b}\)。如果我们知道相对残差 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{b}\|}\) 是 \(10^{-4}\),确定输出相对误差的上限。假设 2-范数。
答案
$\frac{|\Delta \boldsymbol{x}|}{|\boldsymbol{x}|} \le \text{cond}({\bf A})\frac{|\boldsymbol{r}|}{|\boldsymbol{b}|} = \mathbf{15 * 10^{-4}} $
相对残差的替代定义
作为提醒,相对残差 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{b}\|}\) 告诉我们近似解 \(\hat{\boldsymbol{x}}\) 满足线性系统 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的程度。
还有其他一些与“相对残差”密切相关的量,也具有相同的名称。请注意,
总结来说,
我们可以将这个不等式除以 \(\|\boldsymbol{x}\|\) 来得到
量 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{A}\|\cdot\|\boldsymbol{x}\|}\) 也被称为相对残差。这个不等式在数学上是有用的,但它涉及到未知解的范数 \(\|\mathbf{x}\|\),因此它不是限制相对误差的实际方法。由于 \(\|\boldsymbol{b}\| = \|\boldsymbol{A}\boldsymbol{x}\| \leq \|\boldsymbol{A}\|\cdot \|\boldsymbol{x}\|\),我们有
请注意,在某些选择 \(\boldsymbol{b}\) 的情况下,两边有时是相等的。
我们还可以将 方程 (2) 除以 \(\|\hat{\boldsymbol{x}}\|\) 来得到
左边不再是相对误差(分母现在是近似解的范数,而不是精确解),但右边仍然可以提供一个合理的相对误差估计。它也是可计算的,因为真解的范数没有出现在右边。
因此,量 \(\frac{\|\boldsymbol{r}\|}{\|\boldsymbol{A}\|\cdot\|\hat{\boldsymbol{x}}\|}\) 也被称为相对残差。这在下一节中用来描述残差与矩阵 \(\boldsymbol{A}\) 中的误差之间的关系。
虽然 3 个不同的量都被称为“相对残差”可能会令人困惑,但你应该能够通过上下文确定正在讨论的是哪一个。
带部分主元的高斯消元法保证产生小的残差
当我们使用带部分主元的高斯消元法来计算线性方程组 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 的解并得到一个近似解 \(\hat{\boldsymbol{x}}\) 时,残差向量 \(\boldsymbol{r}\) 满足:
其中 \(E\) 是 \({\bf A}\) 中的向后误差(定义为 \(({\bf A}+E)\hat{\boldsymbol{x}} = \boldsymbol{b}\)),\(c\) 是与 \({\bf A}\) 和 \(\epsilon_{mach}\) 相关的系数,而 \(\epsilon_{mach}\) 是机器精度。
通常情况下,带部分主元时 \(c\) 较小,但无主元时 \(c\) 可以任意大。
因此,无论系统的条件数如何,带部分主元的高斯消元法都会产生小的相对残差。****
更多细节,请参阅 高斯消元与舍入误差。
条件数估计的经验法则
假设我们对线性方程组 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\) 应用部分选主元的高斯消元法和回代,并得到一个计算出的解 \(\hat{\boldsymbol{x}}\)。如果 \({\bf A}\) 和 \(\boldsymbol{b}\) 中的项精确到 \(s\) 位小数,且 \(\text{cond}({\bf A}) \approx 10^w\),那么解向量 \(\hat{\boldsymbol{x}}\) 的元素将精确到大约 \(s-w\) 位小数。
关于这个经验法则的证明,请参阅 David S. Watkins 的《矩阵计算基础》。
示例
如果我们使用部分选主元的高斯消元法来解决条件数为 \(10^{10}\) 的线性方程组 \({\bf A} \boldsymbol{x} = \boldsymbol{b}\),并且假设我们使用 IEEE 双精度且输入精确到机器精度,我们期望在解中能得到多少位准确的小数?
答案
在 IEEE 双精度中,\(\epsilon_{mach} \approx 2.2\times 10^{-16}\),这意味着 \({\bf A}\) 和 \(\boldsymbol{b}\) 中的项精确到 \(\vert\log_{10}(2.2\times 10^{-16})\vert \approx 16\) 位小数。
然后,使用这个经验法则,我们知道 \(\hat{\boldsymbol{x}}\) 中的项将精确到大约 \(16-10 = 6\) 位小数。
复习问题
-
条件数的定义是什么?
-
解方程 \({\bf A}\mathbf{x} = \mathbf{b}\) 的条件数是多少?
-
矩阵-向量乘法的条件数是多少?
-
计算给定 \(p\) 的矩阵的 \(p\)-范数条件数。
-
你想要一个小的条件数还是大的条件数?
-
正交矩阵的条件数是多少?
-
如果你 \({\bf A}\) 和 \(\mathbf{b}\) 有 \(p\) 位准确数字,那么当 \({\bf A}\) 的条件数为 \(\kappa\) 时,你在 \({\bf A}\mathbf{x} = \mathbf{b}\) 的解中会有多少位准确数字?
-
在解线性方程组 \({\bf A}\mathbf{x} = \mathbf{b}\) 时,小的残差是否保证结果准确?
-
考虑解线性方程组 \({\bf A}\mathbf{x} = \mathbf{b}\)。何时使用部分选主元的高斯消元法会产生小的残差?
-
矩阵 \({\bf A}\) 的条件数与 \({\bf A}^{-1}\) 的条件数有何关系?
更新日志
-
2024 年 2 月 12 日:Arnav Aggarwal (arnava4) — 将笔记与幻灯片对齐并添加了额外的示例
-
2022 年 3 月 19 日:Yuxuan Chen (yuxuan19) — 添加了条件数要点,进行了一些小的修正
-
2017 年 10 月 27 日:Yu Meng (yumeng5) — 首次完整草案
查看剩余条目
+ 2017 年 10 月 27 日:Erin Carrier (ecarrie2) — 添加复习问题,全文小修,修订了经验法则措辞
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概要
作者
- CS 357 课程工作人员
特征值和特征向量
学习目标
-
为各种应用计算特征值/特征向量。
-
使用幂方法找到特征向量。
-
特征值/特征向量的定义。
-
获取特征值的方法。
-
为各种应用计算特征值/特征向量。
-
使用幂方法找到特征向量。
特征值和特征向量
一个 \(n \times n\) 矩阵 \(\mathbf{A}\) 的特征值是一个标量 \(\lambda\),使得对于某个非零向量 \({\bf x}\),有 \(\mathbf{A} {\bf x} = \lambda {\bf x}\)。特征值 \(\lambda\) 可以是任何实数或复数标量(我们写作 \(\lambda \in \mathbb{R}\ \text{或 } \lambda \in \mathbb{C}\))。即使矩阵 \(\mathbf{A}\) 的所有项都是实数,特征值也可以是复数。在这种情况下,相应的向量 \({\bf x}\) 必须具有复数值分量(我们写作 \({\bf x}\in \mathbb{C}^n\))。方程 \(\mathbf{A}\mathbf{x}=\lambda\mathbf{x}\) 被称为特征值方程,任何这样的非零向量 \({\bf x}\) 被称为 \(\mathbf{A}\) 对应于 \(\lambda\) 的特征向量。
可以将特征值方程重新排列为 \((\mathbf{A} - \lambda {\bf I}) {\bf x} = 0\),由于 \({\bf x}\) 不为零,因此当且仅当 \(\lambda\) 是特征方程的解时,才有解:
表达式 \(p(\lambda) = \operatorname{det}(\mathbf{A} - \lambda {\bf I})\) 被称为特征多项式,是一个 \(n\) 次的多项式。
虽然可以通过求解特征方程找到所有特征值,但对于 \(n \ge 5\) 的多项式的根没有一般形式的封闭形式的解析解,这也不是寻找特征值的好数值方法。
除非另有说明,我们按大小顺序写出特征值,即
我们对特征向量进行归一化,使得 \(\|{\bf x}\| = 1\)。
我们定义 \(A\) 的零空间为 \(\mathbf {Ax}= \mathbf{0}\) 的解的线性组合的生成空间,或所有线性组合的集合。
示例:求解小矩阵以找到特征值
如果矩阵相对较小,我们可以高效地找到行列式并求解特征多项式。
第二,我们通过求解 \(\bf A-\bf I\lambda\) 的平凡解(零空间)来找到每个特征值对应的特征向量。注意以下任何 \(\bf x\) 的倍数都是其特征值的有效特征向量。
对角化性
一个 \(n \times n\) 矩阵,如果它有 \(n\) 个线性无关的特征向量,可以表示为其特征值和特征向量的形式:
特征向量矩阵可以求逆以获得 \(\mathbf{A}\) 的以下 相似变换:
将矩阵 \(\mathbf{A}\) 左乘以 \(\mathbf{X}^{-1}\) 和右乘以 \(\mathbf{X}\) 将其转换为对角矩阵;它已经被“对角化”。
示例:可对角化的矩阵
一个 \(n \times n\) 矩阵是可对角化的当且仅当它有 \(n\) 个线性无关的特征向量。例如:
示例:不可对角化的矩阵
一个具有线性相关特征向量的矩阵 \(\mathbf{A}\) 是不可对角化的。例如,虽然以下说法是正确的:
矩阵 \(\mathbf{X}\) 没有逆矩阵,所以我们不能通过应用逆矩阵来对 \(\mathbf{A}\) 进行对角化。事实上,对于任何非奇异矩阵 \(\mathbf{P}\),乘积 \(\mathbf{P}^{-1}\mathbf{AP}\) 也不是对角矩阵。
示例:对角化矩阵(代码片段)
以下代码片段在可能的情况下对角化一个方阵,请注意,特征向量作为二维 numpy 数组的列存储。
import numpy as np
import numpy.linalg as la
def diagonalize(A):
# A: nxn matrix
m, n = np.shape(A)
if (m != n):
return None
evals, evecs = la.eig(A) # eigenvectors as columns
if (la.matrix_rank(evecs) != n):
return None
D = np.diag(evals)
X = evecs
return (D, X)
关于特征值需要记住的事项
-
特征值可以取零值。
-
特征值可以是负数。
-
特征值可以是实数或复数。
-
一个 \(n \times n\) 的实矩阵可以具有复特征值。
-
\(n \times n\) 矩阵的特征值不一定唯一。实际上,我们可以定义特征值的重数。特征向量 \(\lambda\) 的几何重数对应于 \(\lambda\) 的线性无关特征向量的数量。
-
如果一个 \(n \times n\) 矩阵有 \(n\) 个线性无关的特征向量,那么该矩阵是可对角化的。因此,秩亏矩阵仍然可能是可对角化的。
可对角化的条件
-
如果一个 \(n \times n\) 矩阵 \(\mathbf A\) 有 \(n\) 个线性无关的特征向量 \(\mathbf x\),那么 \(\mathbf A\) 是可对角化的。
-
如果一个 \(n \times n\) 矩阵的特征向量少于 \(n\) 个,那么该矩阵被称为病态的(因此不可对角化)。
-
如果一个 \(n \times n\) 矩阵有 \(n\) 个不同的特征值,那么 A 是可对角化的。
平移矩阵的特征值
给定一个矩阵 \(\mathbf{A}\),对于任何常数标量 \(\sigma\),我们定义 平移矩阵 是 \(\mathbf{A} - \sigma {\bf I}\)。如果 \(\lambda\) 是 \(\mathbf{A}\) 的一个特征值,其特征向量为 \({\bf x}\),那么 \(\lambda - \sigma\) 是平移矩阵的一个特征值,其特征向量相同。这可以通过以下方式推导出来:
逆矩阵的特征值
可逆矩阵不能有等于零的特征值。等于零的特征值将意味着 \(\mathbf{Ax}=\mathbf{b}\) 的平凡解,一个非零维数的零空间,因此一个不可逆矩阵。此外,逆矩阵的特征值等于原矩阵特征值的倒数:
平移逆矩阵的特征值
同样,我们可以描述平移逆矩阵的特征值:
在这里需要注意的是,对于平移或/和逆矩阵,特征向量保持不变。
将任意向量表示为特征向量的线性组合
如果一个 \(n\times n\) 矩阵 \(\mathbf{A}\) 是可对角化的,那么我们可以将任意向量表示为 \(\mathbf{A}\) 的特征向量的线性组合。设 \({\bf u}_1,{\bf u}_2,\dots,{\bf u}_n\) 是 \(\mathbf{A}\) 的 \(n\) 个线性无关的特征向量;那么任意向量 \(\mathbf{x}_0\) 可以表示为:
如果我们将矩阵 \(\mathbf{A}\) 应用于 \(\mathbf{x}_0\):
如果我们反复应用 \(\mathbf{A}\),则有
在一个特征值的模严格大于其他所有特征值的情况下,即
\(\vert\lambda_1\vert > \vert\lambda_2\vert\geq \vert\lambda_3\vert \geq \dots \geq\vert\lambda_n\vert\),
这意味着
显然,当我们反复将 \(\mathbf{A}\) 应用到一个任意向量上——这个向量总是可以由 \(n\) 个线性无关的特征向量组成,这些特征向量张成 \(\mathbb{R}^n\) ——结果收敛到 \(\mathbf{A}\) 的主导特征向量的一个倍数:\(\bf{u_1}\)。这一观察启发了一种称为幂迭代的算法,这是下一节的主题。
幂迭代算法
对于一个矩阵 \({\bf A}\),幂迭代将找到一个特征向量 \({\bf u}_1\) 的标量倍,对应于主导特征值(模最大的)\(\lambda_1\),前提是 \(\vert\lambda_1\vert\) 严格大于其他特征值的模,即 \(\vert\lambda_1\vert > \vert\lambda_2\vert \ge \dots \ge \vert\lambda_n\vert\).
假设
从上一节,迭代序列
满足
因此,对于大的 \(k\),我们有 \(\mathbf{x}_k\approx \lambda_1^k \alpha_1\mathbf{u}_1\)。不幸的是,这意味着 \(\|\mathbf{x}_k\| \approx |\lambda_1|^k\cdot\|\alpha_1\mathbf{u}_1\|,\) 如果 \(|\lambda_1| > 1\),这将非常大,如果 \(|\lambda_1| < 1\),这将非常小。因此,我们使用归一化幂迭代。
归一化幂迭代,由以下给出。设 \(\mathbf{x}_0\) 是一个单位范数的向量:\(\|\mathbf{x}_0\| = 1\)(任何范数都行),且 \(\mathbf{x}_0 = \alpha_1 \mathbf{u}_1 + \alpha_2\mathbf{u}_2 + \dots \alpha_n\mathbf{u}_n,\text{ and }\alpha_1 \neq 0\).
归一化幂迭代定义为以下迭代序列,对于 \(k=1,2,3,\dots\):
其中范数 \(\|\cdot\|\) 与我们假设 \(\|\mathbf{x}_0\| = 1\) 时使用的范数相同。
可以证明这个序列满足
这意味着对于大的 \(k\) 值,我们有
最大的特征值可能是正数、负数或复数。在每种情况下,我们都会有:
严格来说,归一化幂迭代只有在 \(\lambda_1 > 0\) 时才收敛到单个向量,但无论主导特征值是正数、负数还是复数,\(\mathbf{x}_k\) 都会接近特征向量 \(\mathbf{u}_1\) 的一个标量倍,对于大的 \(k\) 值。因此,归一化幂迭代对于任何 \(\lambda_1\) 值都有效,只要它的绝对值比其他特征值大。
幂迭代代码
以下代码片段执行幂迭代:
import numpy as np
def power_iter(A, x_0, p):
# A: nxn matrix, x_0: initial guess, p: type of norm
x_0 = x_0/np.linalg.norm(x_0,p)
x_k = x_0
for i in range(max_iterations):
y_k = A @ x_k
x_k = y_k/np.linalg.norm(y_k,p)
return x_k
示例:幂迭代的两步
我们将使用归一化幂迭代(使用无穷范数)来逼近以下矩阵的特征向量:\(\mathbf{A} = \begin{bmatrix} 1 & -2 \\ -1 & 1 \end{bmatrix}\),以及以下初始猜测:\(\mathbf{x}_0 = \begin{bmatrix} -1 \\ 0 \end{bmatrix}\)
第一次迭代:
第二次迭代:
即使只有两次迭代,我们也在接近相应的特征向量:
当用无穷范数测量时,相对误差约为 4%。
从特征向量计算特征值
力迭代允许我们找到对应于最大特征值(模)的近似特征向量。我们如何从这个近似特征向量计算实际的特征值呢?
如果 \(\lambda\) 是 \(\mathbf{A}\) 的一个特征值,对应的特征向量为 \(\mathbf{u}\),那么我们可以使用 瑞利商 来计算 \(\lambda\) 的值:
因此,可以使用在幂迭代过程中找到的近似特征向量来计算一个近似特征值。
力迭代与浮点运算
回想一下,我们假设初始猜测满足
如果我们选择的初始猜测中 \(\alpha_1 = 0\) 会发生什么?如果我们进一步假设 \(\vert\lambda_2\vert > \vert\lambda_3\vert\geq \vert\lambda_4\vert \geq \dots \geq\vert\lambda_n\vert\),那么在理论上
我们预计
实际上,这种情况不会发生。一方面,如果我们对特征向量 \(\mathbf{u}_1\) 没有先验知识,选择一个 \(\alpha_1 = 0\) 的初始猜测几乎是不可能的。由于幂迭代是数值上进行的,使用有限精度算术,我们将在每次迭代中遇到舍入误差的存在。这意味着在每次迭代 \(k\)(包括 \(k = 0\)),我们实际上将会有
其中 \(\hat{\alpha}_k\) 是舍入结果的近似展开系数。即使 \(\alpha_1 = 0\),有限精度的表示 \(\hat{\mathbf{x}}_0\),很可能具有展开系数 \(\hat{\alpha}_1 \neq 0\)。即使在舍入初始猜测不会引入非零 \(\hat{\alpha}_1\) 的情况下,在足够多的迭代后,舍入应用矩阵 \(\mathbf{A}\) 后几乎肯定会在主导特征向量中引入一个非零分量。得到一个起始猜测 \(\mathbf{x}_0\),使得所有迭代中 \(\hat{\alpha}_1 = 0\) 的概率非常非常低,如果不是不可能的话。
没有主特征值的幂迭代
在上面,我们假设一个特征值的模严格大于所有其他特征值:\(\vert\lambda_1\vert > \vert\lambda_2\vert\geq \vert\lambda_3\vert \geq \dots \geq\vert\lambda_n\vert\)。如果 \(\vert\lambda_1\vert = \vert\lambda_2\vert\) 会发生什么?
如果 \(\lambda_1 = \lambda_2 = \lambda \in \mathbb{R}\),那么:
因此
量 \(\alpha_1\mathbf{u}_1 + \alpha_2\mathbf{u}_2\) 仍然是对应于 \(\lambda\) 的特征向量,因此幂迭代仍然会趋近于主特征向量。
如果主特征值具有相反的符号,即 \(\lambda_1 = -\lambda_2 = \lambda \in \mathbb{R}\),那么
对于大的 \(k\),我们将有 \(\lambda^{-k}\mathbf{A}\mathbf{x}_0 \approx \alpha_1\mathbf{u}_1 + (-1)^k\alpha_2\mathbf{u}_2\),尽管它是两个特征向量的线性组合,但它本身 不是 \(\mathbf{A}\) 的特征向量。
最后,如果两个主特征值是复共轭对 \(\lambda_1 = re^{i\theta},\ \lambda_2 = re^{-i\theta}\),那么 \(\mathbf{x}_k = \mathbf{A}^k\mathbf{x}_0 \approx \alpha_1\lambda^k\mathbf{u}_1 + \alpha_2(\overline{\lambda})^k\mathbf{u}_2 = \lambda^k\left(\alpha_1\mathbf{u}_1 + \left(\frac{\overline{\lambda}}{\lambda}\right)^k\alpha_2\mathbf{u}_2\right) = \lambda^k(\alpha_1\mathbf{u}_1 + \alpha_2 e^{-i2k\theta}\mathbf{u}_2).\)
对于大的 \(k\),\(\lambda^{-k}\mathbf{A}\mathbf{x}_0\) 近似为两个特征向量的线性组合,但这种线性组合本身 不是 特征向量。
逆迭代
为了获得对应于非奇异矩阵的 最小 特征值 \(\lambda_n\) 的特征向量,我们可以对 \(\mathbf{A}^{-1}\) 应用幂迭代。以下递推关系描述了逆迭代算法:\(\boldsymbol{x}_{k+1} = \frac{\mathbf{A}^{-1} \boldsymbol{x}_k}{\|\mathbf{A}^{-1} \boldsymbol{x}_k\|}.\) 不要忘记对每个 \(\boldsymbol{x}_{k+1}\) 进行归一化。
在实践中,我们不是取逆并用于幂迭代,而是对 \(\mathbf{A}\) 进行 LU 分解,并对每次迭代进行 LU 解,将每次迭代的运行时间从 \(O(n³)\) 降低到 \(O(n²)\),预处理仍然是 \(O(n³)\)。
带平移的逆迭代
为了获得与某个值 \(\sigma\) 最接近的特征值对应的特征向量,可以将 \(\mathbf{A}\) 平移 \(\sigma\) 并求逆,以便类似于幂迭代算法来求解。以下递推关系描述了逆迭代算法:\(\boldsymbol{x}_{k+1} = \frac{(\mathbf{A} - \sigma \mathbf{I})^{-1} \boldsymbol{x}_k}{\|(\mathbf{A} - \sigma \mathbf{I})^{-1} \boldsymbol{x}_k\|}\)。注意,如果平移为零,则这与逆迭代相同。
瑞利商迭代
可以根据当前特征值的估计值更新平移 \(\sigma\) 以提高收敛速度。这种估计可以通过瑞利商得到。瑞利商迭代由以下递推关系给出:
收敛性质
功迭代法的收敛率是线性的,当前迭代与主特征向量之间误差的递推关系为:\(\mathbf{e}_{k+1} \approx \frac{|\lambda_2|}{|\lambda_1|}\mathbf{e}_k\)。
(平移的)逆迭代法的收敛率也是线性的,但现在取决于与平移 \(\sigma\) 最接近的两个特征值。(记住,标准逆迭代对应于平移 \(\sigma = 0\)。)误差的递推关系为:\(\mathbf{e}_{k+1} \approx \frac{|\lambda_\text{closest} - \sigma|}{|\lambda_\text{second-closest} - \sigma|}\mathbf{e}_k\)。
成本和收敛性摘要
| 方法 | 描述 | 成本 | 收敛性 |
|---|---|---|---|
| 功方法 | \(\boldsymbol{x}_{k+1} = \mathbf{A} \boldsymbol{x}_{k}\) | \(kn²\) | $\left | \frac{\lambda_2}{\lambda_1}\right | $ |
| 逆幂方法 | \(\mathbf{A} \boldsymbol{x}_{k+1} = \boldsymbol{x}_{k}\) | \(n^{3} + kn²\) | $\left | \frac{\lambda_n}{\lambda_{n-1}}\right | $ |
| 平移逆幂方法 | \((\mathbf{A} - \sigma \mathbf{I}) \boldsymbol{x}_{k+1} = \boldsymbol{x}_{k}\) | \(n^{3} + kn²\) | $\left | \frac{\lambda_c-\sigma}{\lambda_{c2}-\sigma}\right | $ |
\(\lambda_1\): 最大的特征值(按大小)
\(\lambda_2\): 第二大的特征值(按大小)
\(\lambda_n\): 最小的特征值(按大小)
\(\lambda_{n-1}\): 第二小的特征值(按大小)
\(\lambda_c\): 最接近 \(\sigma\) 的特征值
\(\lambda_{c2}\): 最接近 \(\sigma\) 的第二个特征值
正交矩阵
方阵被称为正交的,当且仅当其列向量彼此正交且范数为 \(1\)(这样的向量集形式上称为正交归一集),即:\(\boldsymbol{c}_i^T \boldsymbol{c}_j = 0 \quad \forall \ i \neq j, \quad \|\boldsymbol{c}_i\| = 1 \quad \forall \ i \iff \mathbf{A} \in \mathcal{O}(n),\) 或者 \(\langle\boldsymbol{c}_i,\boldsymbol{c}_j \rangle = \begin{cases} 0 \quad \mathrm{if} \ i \neq j, \\ 1 \quad \mathrm{if} \ i = j \end{cases} \iff \mathbf{A} \in \mathcal{O}(n),\) 其中 \(\mathcal{O}(n)\) 是所有 \(n \times n\) 的正交矩阵的集合,称为正交群,\(\boldsymbol{c}_i\), \(i=1, \dots, n\) 是 \(\mathbf{A}\) 的列向量,\(\langle \cdot, \cdot \rangle\) 是内积算子。正交矩阵具有许多理想的性质:
(a) \(\mathbf{A}^T \in \mathcal{O}(n)\)
(b) \(\mathbf{A}^T \mathbf{A} = \mathbf{A} \mathbf{A}^T = \mathbf{I} \implies \mathbf{A}^{-1} = \mathbf{A}^T\)
(c) \(\det{\mathbf{A}} = \pm 1\)
(d) \(\kappa_2(\mathbf{A}) = 1\)
Gram-Schmidt
从一组线性无关的向量构造正交基的算法称为 Gram-Schmidt 过程。对于一个基集 \(\{x_1, x_2, \dots x_n\}\),我们可以通过以下变换形成一个正交集 \(\{v_1, v_2, \dots v_n\}\):
\(\begin{align} \boldsymbol{v}_1 &= \boldsymbol{x}_1, \\ \boldsymbol{v}_2 &= \boldsymbol{x}_2 - \frac{\langle\boldsymbol{v}_1,\boldsymbol{x}_2\rangle}{\|\boldsymbol{v}_1\|²}\boldsymbol{v}_1,\\ \boldsymbol{v}_3 &= \boldsymbol{x}_3 - \frac{\langle\boldsymbol{v}_1,\boldsymbol{x}_3\rangle}{\|\boldsymbol{v}_1\|²}\boldsymbol{v}_1 - \frac{\langle\boldsymbol{v}_2,\boldsymbol{x}_3\rangle}{\|\boldsymbol{v}_2\|²}\boldsymbol{v}_2,\\ \vdots &= \vdots\\ \boldsymbol{v}_n &= \boldsymbol{x}_n - \sum_{i=1}^{n-1}\frac{\langle\boldsymbol{v}_i,\boldsymbol{x}_n\rangle}{\|\boldsymbol{v}_i\|²}\boldsymbol{v}_i, \end{align}\)
其中 \(\langle \cdot, \cdot \rangle\) 是内积算子。新正交集 \(\{v_1, v_2, \dots v_n\}\) 中的每个向量都可以独立地归一化,以获得正交归一基。
复习问题
-
自主值/特征向量对的定义是什么?
-
如果 \(\mathbf{v}\) 是 \(\mathbf{A}\) 的一个特征向量,对于任何非零标量 \(c\),我们可以说关于 \(c\mathbf{v}\) 什么?
-
\(\mathbf{A}\) 的特征值与以下特征值之间的关系是什么?1) 对于某个标量 \(c\),\(c\mathbf{A}\) 的特征值,2) 对于某个标量 \(\sigma\),\((\mathbf{A} - \sigma \mathbf{I})\) 的特征值,3) \(\mathbf{A}^{-1}\) 的特征值?
-
\(\mathbf{A}\) 的特征向量与以下特征向量之间的关系是什么?1) 对于某个标量 \(c\),\(c\mathbf{A}\) 的特征向量,2) 对于某个标量 \(\sigma\),\((\mathbf{A} - \sigma \mathbf{I})\) 的特征向量,3) \(\mathbf{A}^{-1}\) 的特征向量?
-
能够运行归一化幂迭代的一步或几步。
-
力迭代收敛到 \(\mathbf{A}\) 的哪个特征向量?
-
逆幂迭代收敛到 \(\mathbf{A}\) 的哪个特征向量?
-
带位移的逆幂迭代收敛到 \(\mathbf{A}\) 的哪个特征向量?
-
描述逆迭代法的成本。
-
如果我们给定 \((\mathbf{A} - \sigma \mathbf{I})\) 的 LU 分解,描述逆迭代法的成本。
-
在什么情况下幂迭代(或归一化幂迭代)会失败?
-
给定一个近似特征向量,我们如何近似 \(\mathbf{A}\) 的特征值?
-
如果我们在幂迭代过程中不对迭代进行归一化,会发生什么?
-
什么是雷利商?
-
如果初始猜测没有主特征向量的任何分量,幂迭代的结果会发生什么?这取决于我们使用的是有限精度还是无限精度吗?
-
幂迭代的收敛速度是多少?
-
幂迭代的收敛如何依赖于特征值?
-
我们如何找到矩阵的其他特征值,而不仅仅是主特征值?
-
矩阵可对角化意味着什么?
-
所有矩阵都可以对角化吗?
更新日志
-
2025 年 10 月 28 日:Dev Singh(dsingh14)— 修复特征向量计算
-
2024 年 2 月 13 日:Pascal Adhikary(pascala2)— 添加来自幻灯片的信息/示例,重新组织
-
2022 年 2 月 28 日:陈宇轩(yuxuan19)— 添加学习目标,成本摘要
查看剩余条目
+ 2020 年 3 月 1 日:Peter Sentz()— 添加文本以包含幻灯片内容
+ 2018 年 10 月 14 日:Erin Carrier(ecarrie2)— 删除正交/GS 部分
+ 2018 年 1 月 14 日:Erin Carrier(ecarrie2)— 删除演示链接
+ 2017 年 11 月 10 日:Erin Carrier(ecarrie2)— 添加方法成本
+ 2017 年 10 月 26 日:Matthew West(mwest)— 重写 eval/evec 定义
+ 2017 年 10 月 25 日:Erin Carrier(ecarrie2)— 进行小修,添加复习问题
+ 2017 年 10 月 16 日:Luke Olson(lukeo)— 概述
+ 2017 年 10 月 14 日:Arun Lakshmanan(lakshma2)— 首次完整草案
作者
- CS 357 课程工作人员
马尔可夫链
学习目标
-
为无向图、有向图和加权图创建邻接矩阵。
-
识别并表示随机模型为马尔可夫链。
-
实现 PageRank 算法。
图
图作为矩阵:
在抽象层面上,图是一组对象,其中对象对以某种方式相关。在这里,图简单地表现为节点(顶点)和连接它们的边。将这种信息——节点之间的关系——存储在矩阵中可能非常有帮助。为此,我们使用邻接矩阵。
无向图:
以下是一个无向图的示例:

无向图的邻接矩阵 \({\bf A}\) 总是对称的,定义为:
其中 \(a_{ij}\) 是 \({\bf A}\) 的 \((i,j)\) 元素。描述上述示例图的邻接矩阵为:
有向图:
以下是一个有向图的示例:

有向图的邻接矩阵 \({\bf A}\) 定义为:
其中 \(a_{ij}\) 是 \({\bf A}\) 的 \((i,j)\) 元素。这个矩阵通常是反对称的,因此遵守定义很重要。注意,虽然我们实际上使用列来表示“从”节点,行来表示“到”节点,但这并不一定是标准的,你可能会遇到相反的方向。描述上述示例图的邻接矩阵为:
加权有向图:
以下是一个加权有向图的示例:

加权有向图的邻接矩阵 \({\bf A}\) 定义为:
其中 \(a_{ij}\) 是 \({\bf A}\) 的 \((i,j)\) 元素,\(w_{ij}\) 是连接节点 \(i\) 和 \(j\) 的边的链接权重。描述上述示例图的邻接矩阵为:
通常,当我们讨论加权有向图时,是在马尔可夫链的转移矩阵的上下文中,其中每列的链接权重之和为 \(1\)。
马尔可夫链
马尔可夫链是一种随机模型,其中未来(下一个)状态的概率只依赖于最近(当前)状态。这种随机过程的记忆性特性被称为马尔可夫性质。从概率的角度来看,马尔可夫性质意味着未来状态的条件概率分布(基于过去和当前状态)只依赖于当前状态。
马尔可夫性质,更正式地可以写成:
马尔可夫矩阵
马尔可夫/转移/随机矩阵是一个用于描述马尔可夫链转移的方阵。它的每个条目都是一个非负实数,代表一个概率。基于马尔可夫性质,下一个状态向量 \({\bf x}_{k+1}\) 是通过将马尔可夫矩阵 \({\bf M}\) 左乘以当前状态向量 \({\bf x}_k\) 得到的。
在本课程中,除非特别说明,我们定义转移矩阵 \({\bf M}\) 为一个左马尔可夫矩阵,其中每一列的和为 \(1\)。或者,我们可以说每一列的 \(1\text{-}范数\) 为 \(1\)。
注意:外部资源中的其他定义可能将 \({\bf M}\) 表示为右马尔可夫矩阵,其中 \({\bf M}\) 的每一行之和为 \(1\),并且下一个状态是通过右乘 \({\bf M}\) 得到的,即 \({\bf x}_{k+1}^T = {\bf x}_k^T {\bf M}\)。
一个稳态向量 \({\bf x}^*\) 是一个概率向量(条目非负且总和为 \(1\)),在马尔可夫矩阵 \(M\) 的操作下保持不变,即
因此,稳态向量 \({\bf x}^*\) 是对应于矩阵 \({\bf M}\) 的特征值 \(\lambda=1\) 的特征向量。如果有多个特征值 \(\lambda=1\) 的特征向量,那么相应稳态向量的加权平均值也将是一个稳态向量。因此,马尔可夫链的稳态向量可能不是唯一的,并且可能依赖于初始状态向量。
总结来说,状态向量 \({\bf x}\) 与马尔可夫矩阵 \({\bf M}\) 从左向右的重复乘法收敛到特征值 \(\lambda=1\) 的向量。这应该会让你想起幂迭代方法。马尔可夫矩阵按大小排序的特征值总是 1。
马尔可夫链示例:天气
假设我们想要为 UIUC 夏季的天气预测构建一个马尔可夫链模型。我们观察到:
-
一个晴天有 \(60\%\) 的可能性接着又是晴天,\(10\%\) 的可能性接着是雨天,\(30\%\) 的可能性接着是阴天;
-
一个雨天有 \(40\%\) 的可能性接着又是雨天,\(20\%\) 的可能性接着是晴天,\(40\%\) 的可能性接着是阴天;
-
一个阴天有 \(40\%\) 的可能性接着又是阴天,\(30\%\) 的可能性接着是雨天,\(30\%\) 的可能性接着是晴天。
状态图如下所示:

马尔可夫矩阵是
如果已知第 \(0\) 天的天气是雨天,那么
我们可以通过以下方式确定第 \(1\) 天的概率向量:
第 \(n\) 天天气的概率分布由以下给出
马尔可夫链示例:Page Rank
Page Rank 是一个简单的算法,它被 Google 搜索推广,用于网页排名。它试图通过假设一个随机访问者会连续随机点击链接来模拟用户行为。因此,一个网页的重要性由随机用户最终到达该页面的概率决定。

让上面的图表示网站为节点,出站链接为有向边。首先,我们创建一个邻接矩阵。
接下来,我们取一个给定页面的累积权重(影响力),并将其平均分配到每个出站链接。这是一个马尔可夫矩阵。和之前一样,我们可以对一个随机状态向量进行重复迭代,直到达到稳态,以找到用户最有可能到达的页面。
如果一个站点被其他“重要”站点链接,那么这个站点就会变得“重要”。直觉上大致可以这样理解:如果一个站点 \(s\) 被嵌入在一个很少被嵌入的另一个站点中,那么站点 \(s\) 的排名不会增加太多。相反,如果一个站点 \(s\) 被嵌入在更受欢迎的站点中,它的排名将会增加。
Naive Page Rank:缺点
这种 Page Rank 的简单实现的一个弱点是,不能保证有唯一解。布林-佩奇(1990 年代)提出了:
“PageRank 可以被视为用户行为的一个模型。我们假设有一个随机访问者,他被随机分配到一个网页,并持续点击链接,从不点击“后退”,但最终会感到无聊并开始访问另一个随机页面。”
我们引入一个常数,或阻尼系数,\(d\),以模拟随机跳跃。设\(n\)为图中节点的数量。在这里,冲浪者以概率\(d\)点击当前页面上的链接,以概率\(1-d\)打开一个随机页面。此模型使得 M 的所有条目都大于零,并保证有唯一解。
复习问题
-
给定一个无向或有向图(加权或无权),确定图的邻接矩阵。
-
什么是转移矩阵?给定表示转换或问题描述的图,确定转移矩阵。
更新日志
-
2024 年 3 月 3 日:Pascal Adhikary (pascala2) — 添加幻灯片信息,页面排名
-
2018 年 4 月 1 日:Erin Carrier (ecarrie2) — 进行小规模重组和格式更改
-
2018 年 3 月 25 日:Yu Meng (yumeng5) — 添加马尔可夫链
查看剩余条目
+ 2018 年 3 月 1 日:Erin Carrier (ecarrie2) — 添加更多复习问题
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 删除演示链接
+ 2017 年 11 月 2 日:Erin Carrier (ecarrie2) — 添加更新日志,修复 COO 行索引错误
+ 2017 年 10 月 25 日:Arun Lakshmanan (lakshma2) — 第一份完整草案
+ 2017 年 10 月 25 日:Erin Carrier (ecarrie2) — 添加复习问题,进行小修和格式更改
+ 2017 年 10 月 16 日:Luke Olson (lukeo) — 概述
作者
- CS 357 课程工作人员
有限差分方法
原文:
cs357.cs.illinois.edu/textbook/notes/finite-difference.html
学习目标
- 使用有限差分法近似导数
有限差分近似
动机
对于一个给定的光滑函数 \(f(x)\),我们想要计算 \(x\) 的给定值处的导数 \(f'(x)\)。
然而,有时我们不知道如何计算 \(f'(x)\) 的解析表达式,或者计算成本太高。
有限差分方法可以帮助找到 \(f'(x)\) 的近似值。
定义
对于一个可微函数 \(f(x):\mathbb{R} \rightarrow \mathbb{R}\),导数的定义是
我们将前向有限差分近似,\(df(x)\),定义为第一导数
其中 \(h\) 通常被称为“扰动”,即对变量 \(x\) 的“小”变化(与 \(x\) 的大小相比是小)。
通过泰勒定理,我们可以写出
重新排列上述公式,我们得到导数 \(f'(x)\) 作为前向有限差分近似 \(df(x)\) 的函数:
错误
因此,前向有限差分近似的截断误差被限制在以下范围内:
其中 \(M\) 是 \(h\) 值的一个常数界限。
如果 \(h\) 非常小,我们将会遇到舍入误差,其界限为:
其中 \(\epsilon_m\) 是机器精度。
为了找到使总误差最小化的 \(h\):
使用 \(f(x) = e^x - 2\) 上的前向有限差分近似,我们可以从下面的图中看到总误差、截断误差和舍入误差的值,这取决于选择的扰动 \(h\)。

因此,我们可以看到使总误差最小化的最优 \(h\) 是截断误差和舍入误差相交的地方。
使用类似的方法,我们可以总结以下有限差分近似:
前向有限差分法
除了计算 \(f(x)\) 之外,这种方法还需要额外的计算成本,即对一个给定的扰动 \(f(x+h)\) 进行一次函数评估,并且具有截断阶 \(O(h)\)。
示例
假设 \(f(x) = 2x² + 15x + 1\) 并且我们试图在 \(x = 10, h = 0.01\) 处找到 \(df(x)\)。
我们可以通过以下方式找到绝对截断误差:
后向有限差分法
除了计算 \(f(x)\) 的值之外,这种方法还需要额外的计算一个函数值 \(f(x-h)\) 的成本,对于一个给定的扰动,并且具有截断阶数 $O(h) $。
示例
假设 \(f(x) = 2x² + 15x + 1\),我们试图在 \(x = 10, h = 0.01\) 处找到 \(df(x)\)。
我们可以通过以下方式找到绝对截断误差:
中央有限差分法
这种方法需要一个额外的函数评估成本(\(f(x+h)\) 和 \(f(x-h)\)),对于一个给定的扰动,并且具有截断阶数 $O(h²) $。因此,我们可以看到中央有限差分近似提供了更好的精度,但可能增加了计算成本。
示例
假设 \(f(x) = 2x² + 15x + 1\),我们试图在 \(x = 10, h = 0.01\) 处找到 \(df(x)\)。
我们可以通过以下方式找到绝对截断误差:
梯度近似
考虑一个可微函数 \(f(x_1, \dots, x_n):\mathbb{R^n} \rightarrow \mathbb{R}\),其中导数定义为梯度,或者
我们定义梯度有限差分近似为
使用前向有限差分法,其中 $\delta_i $ 是一个在位置 \(i\) 有 \(1\) 而其他地方为 \(0\) 的向量。
注意:$df(x) $ 可以使用任何有限差分方法定义。
示例
假设 \(f(x_1, x_2) = 2x_1 + x_1²x_2 + x_2³\),我们试图在 \(x_1 = 1.3, x_2 = 4.9\) 处,当 \(h = 0.05\) 时找到前向有限差分梯度的近似值。
我们可以通过以下方式找到绝对截断误差:
雅可比近似
考虑一个可微函数 \(f = \begin{bmatrix} f_1(x) & f_2(x) & \dots & f_n(x) \end{bmatrix}:\mathbb{R^n} \rightarrow \mathbb{R^m}\),其中导数定义为雅可比矩阵,或者
我们定义雅可比有限差分近似为
其中 $df_i(x_j) $ 是使用任何有限差分方法在 \(x_j\) 处对 \(f_i\) 的近似。
示例
假设 \(f = \begin{bmatrix} f_1(x) = 2x_1² + 6x_1x_2 & f_2(x) = 3x_1 + 7x_2 \end{bmatrix}\) 并且我们试图在 \(x_1 = 3, x_2 = 7\) 时,当 \(h = 0.1\) 时找到前向有限差分梯度近似。
我们可以通过以下方式找到绝对截断误差:
参考文献:Michael Heath 所著的 "Scientific Computing: an introductory survey"
复习问题
-
泰勒级数的一般形式是什么?
-
你如何使用泰勒级数来近似给定点的函数?
-
你如何使用泰勒级数近似函数的导数?
-
你如何使用泰勒级数近似函数的积分?
-
给定一个函数和一个中心点,你能写出\(n\)次度的泰勒多项式吗?
-
对于一个\(n\)次度的泰勒多项式,你的近似误差作为距离中心的函数的界限是多少?
-
对于简单函数,你能在泰勒误差界限中找到常数\(C\)吗?
-
能够确定为了使泰勒级数近似误差小于某个给定值,需要多少项。
更新日志
-
2024 年 2 月 24 日:Kriti Chandak(kritic3)——从幻灯片和视频中添加了信息,并添加了额外的示例
-
2021 年 1 月 20 日:Mariana Silva(mfsilva)——将 FD 内容从泰勒部分移动到这个新部分
查看剩余条目
作者
- CS 357 课程工作人员
求解非线性方程
学习目标
-
评估二分法、牛顿法和割线法求解一维非线性方程
-
应用牛顿法求解非线性方程组
函数的根
考虑一个函数 \(f : \mathbb{R} \to \mathbb{R}\)。如果 \(f(x) = 0\),则 \(x \in \mathbb{R}\) 被称为 \(f\) 的 根。
方程的求解
找到 \(f(x) = 0\) 的 \(x\) 值对于许多应用很有用,但一个更一般的目标是找到 \(f(x) = y\) 的 \(x\) 值。用于找到函数根的技术可以用来通过操纵函数来解方程,如下所示:
新函数 \(\tilde{f}(x)\) 在原方程 \(f(x) = y\) 的解处有一个根。
一维非线性方程
线性函数很容易求解,如果你记住了二次公式,二次函数也容易求解。然而,高次多项式和非多项式函数的求解要困难得多。求解这些类型方程的最简单技术是使用迭代求根技术。我们不会直接找出 \(f(x) = 0\) 的位置,而是从一个初始猜测开始,并在多个步骤中逐步改进,直到我们的 残差 \(f(x)\) 足够小。
收敛性
一个迭代方法以 \(\mathbf r\) 的速率收敛,如果:
其中 \(e_k\) 是第 k 次迭代的误差。
线性收敛每一步增加一个常数数量的准确数字(误差线性减小)。当 \(C\) 接近 1 时,收敛速度慢。
二次收敛使每一步的准确数字数量加倍(误差呈二次减小)。然而,它只有在 \(\|e^k\|\) 很小的时候才有意义,而 C 并不重要。
示例
幂迭代的收敛速率是多少?
答案
从幂迭代方法中回忆
我们看到当 \({\mathbf r} = 1\) 时,我们得到两个连续迭代之间的比值为常数。因此幂迭代具有线性收敛。
二分法
二分法是最简单的求根技术。
算法
二分法的算法类似于二分查找:
-
在根的两侧取两个点,\(a\) 和 \(b\),使得 \(f(a)\) 和 \(f(b)\) 符号相反。
-
计算中点 \(c = \frac{a + b}{2}\)
-
评估 \(f(c)\) 并使用 \(c\) 替换 \(a\) 或 \(b\),保持端点的符号相反。
使用这个算法,我们每次迭代都依次将包含根的区间的长度减半。我们可以重复这个过程,直到区间的长度小于我们想要知道根的容差。
收敛性
二分法不估计 \(x_{k}\),即所需根 \(x\) 的近似值。它而是找到一个包含根的区间(小于给定的容差)。
因此,迭代 k 的误差定义为 k 次迭代时区间的长度,或 \(\frac{(b - a)}{2^k}\)。
这给出了线性收敛,常数为 \(\frac{1}{2}\)。
计算成本
从概念上讲,二分法在每次迭代中使用 2 次函数评估。然而,在每一步中,\(a\) 或 \(b\) 中的一个保持不变。因此,在每次迭代(第一次迭代之后),在之前的迭代中已经计算了 \(f(a)\) 或 \(f(b)\) 中的一个。因此,二分法每次迭代只需要进行一次新的函数评估。根据函数评估的成本,这可以节省显著的成本。
缺点
二分法要求我们对我们所研究的函数有一定的了解。具体来说,\(f(x)\) 必须是连续的,并且我们必须有一个区间 \([a, b]\),使得
然后,根据介值定理,我们知道在区间 \([a,b]\) 内必须有一个根。
这个限制意味着二分法不能求解 \(x²\) 的根,因为它永远不会穿过 x 轴并变为负数。
示例
答案

从上面的图中,我们可以看到 \(f(x)\) 在 1 和 2 之间有一个根。很难确切知道根是什么,但我们可以使用二分法来近似它。具体来说,我们可以将 \(a = 1\) 和 \(b = 2\)。
迭代 1
由于 \(f(b)\) 和 \(f(c)\) 都是正数,我们将用 \(c\) 替换 \(b\) 并进一步缩小我们的区间。
迭代 2
由于 \(f(a)\) 和 \(f(c)\) 都是负数,我们将用 \(c\) 替换 \(a\) 并进一步缩小我们的区间。
注意,如上所述,我们不需要重新计算 \(f(a)\) 或 \(f(b)\),因为我们已经在之前的迭代中计算了它们。重用这些值可以显著节省成本。
迭代 3
由于 \(f(b)\) 和 \(f(c)\) 都是正的,我们将用 \(c\) 替换 \(b\),并进一步缩小我们的区间。
…
迭代 n
当运行下面的二分法代码时,得到的近似根为 \(1.324717957244502\)。使用二分法,我们可以将根近似到所需的公差(上面的值是默认公差)。
代码
以下 Python 代码调用 SciPy 的 bisect 方法:
import scipy.optimize as opt
def f(x):
return x**3 - x - 1
root = opt.bisect(f, a=1, b=2)
牛顿法
牛顿-拉夫森方法(又称牛顿法)使用函数的泰勒级数近似来寻找一个近似解。具体来说,它取前两项:
算法
从上面的泰勒级数开始,我们可以这样找到这个新函数的根:
这个 \(h\) 值被称为 牛顿步。现在,\(h\) 可以用来执行 牛顿更新,以找到更接近 \(f\) 的根的 \(x\) 值:
几何上,\((x_{k+1}, 0)\) 是 x 轴与 \((x_k, f(x_k))\) 处图形的切线的交点。
通过重复此过程,我们可以越来越接近实际的根。
计算成本
使用牛顿法,在每次迭代中,我们必须评估 \(f(x)\) 和 \(f'(x)\)。
收敛
尽管牛顿法比二分法成本更高,但它收敛得更快。
这给我们带来了二次收敛。然而,正如我们在下一节中看到的,这取决于初始猜测。
缺点
评估导数的额外成本使得每次迭代计算速度变慢。
许多函数不易微分,因此牛顿法并不总是可行。即使在可以评估导数的情况下,它可能也相当昂贵。
收敛只有在您已经接近根的情况下才有效。具体来说,如果起始位置离根太远,牛顿法可能根本不会收敛。
示例
答案

从上面的图中,我们可以看到根大约在 \(x = 1\) 附近。我们将使用 \(x_0\) 作为我们的起始位置。
迭代 1
\(\begin{flalign*} \hspace{2cm} x_1 &= x_0 - \frac{f(x_0)}{f'(x_0)} \\ &= 1 - \frac{f(1)}{f'(1)} &\\ &= 1 - \frac{1³ - 1 - 1}{3 \cdot 1² - 1} \\ &= 1 + \frac{1}{2} \\ &= 1.5 \end{flalign*}\)
迭代 2
\(\begin{flalign*} \hspace{2cm} x_2 &= x_1 - \frac{f(x_1)}{f'(x_1)} \\ &= 1.5 - \frac{f(1.5)}{f'(1.5)} &\\ &= 1.5 - \frac{1.5³ - 1.5 - 1}{3 \cdot 1.5² - 1} \\ &= 1.5 - \frac{0.875}{5.75} \\ &= 1.3478260869565217 \end{flalign*}\)
迭代 3
如您所见,牛顿法已经比二分法收敛得快得多。
…
迭代 n
当运行以下牛顿法代码时,得到的近似根为 \(1.324717957244746\)。
代码
以下 Python 代码调用 SciPy 的 newton 方法:
import scipy.optimize as opt
def f(x):
return x**3 - x - 1
def fprime(x):
return 3 * x**2 - 1
root = opt.newton(f, x0=1, fprime=fprime)
切线法
与牛顿法类似,切线法使用泰勒级数来找到解。然而,您可能并不总是能够对函数求导。切线法通过近似导数来解决这个问题:
算法
切线法涉及的步骤与牛顿法相同,只是将导数替换为切线斜率的近似值。
计算成本
与二分法类似,尽管切线法在概念上需要每迭代一次进行两次函数评估,其中一次函数评估已在上一迭代中计算并可以重用。因此,切线法每迭代一次需要 1 个新的函数评估(第一次迭代之后)。
收敛性
切线法具有超线性收敛性。
更具体地说,收敛率 \(r\) 是:
这恰好是黄金比例。
缺点
这种技术与牛顿法有许多相同的缺点,但不需要导数。它的收敛速度不如牛顿法快。它还需要两个接近根的起始猜测值。
示例
答案

让我们从 \(x_0 = 1\) 和 \(x_{-1} = 2\) 开始。
迭代 1
首先,找到导数(斜率)的近似值:
然后,用这个结果来应用牛顿法:
\(\begin{flalign*} \hspace{0.5cm}x_1 &= x_0 - \frac{f(x_0)}{f'(x_0)} \\ &= 1 - \frac{f(1)}{f'(1)} &\\ &= 1 - \frac{1³ - 1 - 1}{6} \\ &= 1 + \frac{1}{6} \\ &= 1.1666666666666667 \end{flalign*}\)
迭代 2
\(\begin{flalign*} \hspace{0.5cm}x_2 &= x_1 - \frac{f(x_1)}{f'(x_1)} \\ &= 1.1666666666666667 - \frac{f(1.1666666666666667)}{f'(1.1666666666666667)} &\\ &= 1.1666666666666667 - \frac{1.1666666666666667³ - 1.1666666666666667 - 1}{2.5277777777777777} \\ &= 1.1666666666666667 - \frac{-0.5787037037037035}{2.5277777777777777} \\ &= 1.3956043956043955 \end{flalign*}\)
迭代 3
…
迭代 n
当运行以下割线法的代码时,确定的近似根为 \(1.324717957244753\)。
代码
SciPy 的newton方法具有双重功能。如果给定一个函数 \(f\) 和一个一阶导数 \(f'\),它将使用牛顿法。如果没有给定导数,它将改用割线法来近似它:
import scipy.optimize as opt
def f(x):
return x**3 - x - 1
root = opt.newton(f, x0=1)
1D 总结

非线性方程组
与一维的根查找类似,我们也可以在 \(n\) 维中进行多方程的根查找。从数学上讲,我们试图求解 \(\boldsymbol{f(x) = 0}\) 对于 \(\boldsymbol{f} : \mathbb{R}^n \to \mathbb{R}^n\)。换句话说,\(\boldsymbol{f(x)}\) 现在是一个向量值函数
如果我们正在寻找 \(\boldsymbol{f(x) = y}\) 的解,我们可以重新设计我们的函数如下:
我们可以将每个方程视为一个描述曲面的函数。我们正在寻找描述这些曲面交点的向量。
雅可比矩阵
给定 \(\boldsymbol{f} : \mathbb{R}^n \to \mathbb{R}^n\),我们定义雅可比矩阵 \({\bf J}_f\) 为:
牛顿法
牛顿法的多维等价形式涉及将函数近似为:
其中 \({\bf J}_f\) 是 \(\boldsymbol{f}\) 的 雅可比矩阵。
通过将其设置为 \(\mathbf{0}\) 并重新排列,我们得到:
注意,在实践中,我们实际上不会求雅可比矩阵的逆,而是会求解 \((1)\) 中的线性系统以确定步长。
算法
与我们在一维中求解 \(x_{k+1}\) 的方式类似,我们可以求解:
\(\boldsymbol{x_{k+1}} = \boldsymbol{x_k} + \boldsymbol{s_k}\) 其中 \(\boldsymbol{s_k}\) 通过求解线性系统 \({\bf J}_f(\boldsymbol{x_k})\boldsymbol{s_k} = -\boldsymbol{f(x_k)}\) 确定。
缺点
就像在一维中一样,牛顿法只在局部收敛。在每次迭代中计算 \({\bf J}_f\) 也可能很昂贵,并且我们必须在每次迭代中求解一个线性系统。
示例
求解
相应的雅可比矩阵和逆雅可比矩阵为:
在这个例子中,由于雅可比矩阵是一个 \(2 \times 2\) 矩阵,其逆简单,我们明确地使用逆矩阵,即使在实际问题中我们不会明确地计算逆矩阵。
让我们从 \(\boldsymbol{x_0} = \begin{bmatrix}1 \\ 1\end{bmatrix}\) 开始。
迭代 1
\(\begin{flalign*} \hspace{2cm}\boldsymbol{x_1} &= \boldsymbol{x_0} - {\bf J}_f(\boldsymbol{x_0})^{-1} \boldsymbol{f(x_0)} \\ &= \begin{bmatrix}1 \\ 1\end{bmatrix} - \frac{1}{1 - 2}\begin{bmatrix}-2 & \frac{1}{2} \\ \frac{1}{2} & - \frac{1}{4}\end{bmatrix} \begin{bmatrix}1 \\ 1\end{bmatrix} &\\ &= \begin{bmatrix}1 \\ 1\end{bmatrix} + \begin{bmatrix}-1.5 \\ 0.25\end{bmatrix} \\ &= \begin{bmatrix}-0.5 \\ 1.25\end{bmatrix} \end{flalign*}\)
迭代 2
\(\begin{flalign*} \hspace{2cm}\boldsymbol{x_2} &= \boldsymbol{x_1} - {\bf J}_f(\boldsymbol{x_1})^{-1} \boldsymbol{f(x_1)} \\ &= \begin{bmatrix}-0.5 \\ 1.25\end{bmatrix} - \frac{1}{-0.5 - 2.5}\begin{bmatrix}-2.5 & \frac{1}{2} \\ - \frac{1}{4} & - \frac{1}{4}\end{bmatrix} \begin{bmatrix}0 \\ 2.5\end{bmatrix} &\\ &= \begin{bmatrix}-0.5 \\ 1.25\end{bmatrix} + \frac{1}{3}\begin{bmatrix}1.25 \\ -0.625\end{bmatrix} \\ &= \begin{bmatrix}-0.08333333 \\ 1.04166667\end{bmatrix} \end{flalign*}\)
迭代 3
…
迭代 n
在运行以下牛顿法的代码时,确定的近似根为 \(\begin{bmatrix}-2.74060567 \cdot 10^{-16} & 1\end{bmatrix}^\top.\)
代码
import numpy as np
import scipy.optimize as opt
def f(xvec):
x, y = xvec
return np.array([
x + 2*y - 2,
x**2 + 4*y**2 - 4
])
def Jf(xvec):
x, y = xvec
return np.array([
[1, 2],
[2*x, 8*y]
])
sol = opt.root(f, x0=[1, 1], jac=Jf)
root = sol.x
复习问题
-
你如何使用根查找方法来解决非线性方程的某个非根值?
-
对于一个给定的非线性方程(1D),你应该能够运行几个步骤:
-
二分法
-
梯度法
-
牛顿法
-
-
二分法每迭代需要多少次函数评估?
-
二分法的收敛率是多少?它总是会收敛吗?
-
使用二分法,给定一个特定的初始区间 \([a,b]\) 和一个给定的容差 \(tol\),需要多少次迭代才能使近似根达到给定的容差精度?
-
1D 牛顿法根查找每迭代需要多少次函数评估?哪些函数必须被评估?
-
牛顿法在 1D 根查找中的收敛率是多少?
-
梯度法每迭代需要多少次函数评估?
-
割线法的收敛率是多少?它总是会收敛吗?
-
二分法、牛顿法和割线法的优缺点是什么?(例如,为什么你会选择其中一个而不是另一个?)
-
对于给定的向量值函数 \(\mathbf{f}(\mathbf{x})\),雅可比矩阵(在一般情况和特定点上的计算)是什么。
-
对于一个简单的非线性方程组,你应该能够运行一步 \(n\) 维牛顿法。
-
牛顿法在 \(n\) 维根查找中的收敛率是多少?它总是会收敛吗?
-
在 \(n\) 维中,牛顿法每迭代需要哪些操作?
变更日志
-
2024 年 2 月 24 日:Apramey Hosahalli (apramey2) — 对齐方程,添加讲座中的收敛性描述,并添加总结图像
-
2024 年 2 月 24 日:Apramey Hosahalli (apramey2) — 修改示例格式,添加收敛性章节
-
2017 年 12 月 25 日:Adam Stewart (adamjs5@illinois.edu) — 第一份完整草案
查看剩余条目
+ 2017 年 12 月 2 日:Erin Carrier (ecarrie2) — 添加复习问题,添加更多成本信息,一些其他小修复
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概要
作者
- CS 357 课程工作人员
优化
学习目标
-
识别优化的目标:寻找函数最小值的近似值
-
理解基本的优化方法
-
将问题设定为 优化 问题
-
理解一维优化的两种方法:黄金分割搜索 和 牛顿法(一维)
-
理解多维优化的两种方法:最速下降法 和 牛顿法(多维)
-
确定优化中的挑战
优化:寻找函数的最小值
优化的目标是找到函数定义域中的点,使得函数最小化。
考虑一个函数 \(f:\;S\to \mathbb{R}\),其中 \(S\subset\mathbb{R}^n\)。如果 \(\boldsymbol{x}^*\in S\) 是 \(f\) 的最小值或最小化点,当且仅当 \(f(\boldsymbol{x}^*)\leq f(\boldsymbol{x}) \, \forall x\in S\)。
优化有两种类型:
-
无约束优化:找到 \(\boldsymbol{x}^*\) 使得 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\)
-
约束优化:找到 \(\boldsymbol{x}^*\) 使得 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\)
\(\hspace{2cm} \text{such that: } \boldsymbol{g}(\boldsymbol{x}) = 0 \hspace{5mm} \leftarrow \hspace{5mm} \text{\small “等式约束”}\) \(\hspace{2cm} \text{and / or: } \boldsymbol{h}(\boldsymbol{x}) \leq 0 \hspace{5mm} \leftarrow \hspace{5mm} \text{\small “不等式约束”}\)
for some other functions \(\boldsymbol{g}\) and/or \(\boldsymbol{h}\).
注意,如果优化问题的定义域 \(S\) 是无限的,则不一定存在解决方案。
在本主题的其余部分,我们试图找到一个函数的最小值。注意,如果我们想要一个函数 \(\boldsymbol{f}\) 的最大化者 \(\boldsymbol{y}^*\),使得 \(f(\boldsymbol{y}^{*}) = \underset{\boldsymbol{y}}{\mathrm{max}}\hspace{1mm}f(\boldsymbol{y})\),我们可以通过解决最小化问题来找到最小化者 \(\boldsymbol{x}^*\),其中 \(\boldsymbol{x}^*\) 满足 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x}}{\mathrm{min}}(\hspace{1mm}-f(\boldsymbol{x}))\)。
示例:微积分问题
给定 \(d_1, d_2 \gt 0\),找到:
注意到 \(\underset{\boldsymbol{d \in \mathbb{R}²}}{\mathrm{max}}\hspace{1mm}f(d_1, d_2) = \underset{\boldsymbol{d \in \mathbb{R}²}}{\mathrm{min}}\hspace{1mm}(-f(d_1, d_2))\),因此我们可以解决以下优化问题:
更多详情
实际上,这个问题是要求在周长约束(20)下最小化矩形的面积。下面的红色区域给出了一个示例:

下面是 \(d_1\) 和 \(d_2\) 之间面积和周长的关系的可视化:

局部最小值与全局最小值
考虑一个域 \(S\subset\mathbb{R}^n\),以及 \(f:S\to\mathbb{R}\)。
-
局部最小值:如果对所有在 \(\boldsymbol{x}^*\) 的某个邻域内的可行 \(\boldsymbol{x}\),\(\boldsymbol{x}^*\) 是一个局部最小值,则 \(f(\boldsymbol{x}^*)\leq f(\boldsymbol{x})\)。
-
全局最小值:如果对所有 \(\boldsymbol{x}\in S\),\(\boldsymbol{x}^*\) 是一个全局最小值,则 \(f(\boldsymbol{x}^*)\leq f(\boldsymbol{x})\)。
注意,找到局部最小值比找到全局最小值更容易。给定一个函数,在域上找到全局最小值是否存在本身就是一个非平凡的问题。因此,我们将限制自己寻找函数的局部最小值。
此外,请注意,一个函数可以总是有多个最小值。

解决一维优化问题的两种方法类型
首先,让我们了解一些解决一维优化问题的技术。
给定一个非线性、连续且光滑的函数 \(f:\;\mathbb{R}\to \mathbb{R}\) 和优化问题 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x \in S}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\),我们将在这个课程中介绍两种类型的方法:
-
无导数方法:只需在 \(S\) 中的一组 \(x \in S\) 上评估 \(f(\boldsymbol{x})\)。特别是,我们涵盖了黄金分割搜索方法。
-
二阶导数方法:需要评估 \(f(\boldsymbol{x})\)、\(f'(\boldsymbol{x})\) 和 \(f''(\boldsymbol{x})\),以及 \(S\) 中的一组 \(x \in S\)。特别是,我们涵盖了一维牛顿法。
1-D 局部最小值的准则
在一维优化情况下,我们需要找到一个连续且光滑的函数 \(f:\;\mathbb{R} \to \mathbb{R}\) 的最小值。回顾微积分,当 \(f'(x^*) = 0\) 时,如果 \(f''(x^*) < 0\),则得到一个局部最大值;如果 \(f''(x^*) > 0\),则得到一个局部最小值。(注意,如果 \(f''(x^*) = 0\),我们无法得出任何结论)。然后,我们可以通过获取一阶和二阶导数的值来判断点 \(x^* \in S\) 是否是局部最小值(即找到 \(\boldsymbol{x}^*\) 使得 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\))。具体来说,
-
(一阶)必要条件:\(f'(x^*) = 0\)
-
(二阶)充分条件:\(f'(x^*) = 0\) 和 \(f''(x^*) > 0\)。
示例:一维优化问题
考虑函数 \(f(x) = x³ - 6x² + 9x -6\)。
我们如何找到它的局部最小值?
答案
一阶和二阶导数如下:\(f'(x) = 3x²-12x+9\) \(f''(x) = 6x-12\) 驻点如下表所示:
| \({x}\) | \({f'(x)}\) | \({f''(x)}\) | 特征 |
|---|---|---|---|
| 3 | 0 | \(6\) | 局部最小值 |
| 1 | 0 | \(-6\) | 局部最大值 |
从表中可以看出,\(x=3\) 满足局部最小值的充分条件。
示例:找出 1-D 函数的所有驻点
考虑函数 \(f(x) = \frac{x⁴}{4} - \frac{x³}{3} - 11x² + 40x\)。
找到驻点并检查充分条件。
答案
\(f\) 的梯度向量和 Hessian 矩阵如下:\(f'(x) = \frac{4x³}{4} - \frac{3x²}{3} - 22x +40 = x³ - x² - 22x + 40\) \(f''(x) = 3x² - 2x - 22\) 解 \(f'(x) = 0\) 得到三个可能的解,即 \(x_1 = -5, x_2 = 2, \text{和 }x_3 = 4\)。
现在,观察以下:
(1) \(f''(x_1) = 3 \times (-5)² - 2 \times (-5) - 22 \gt 0\) \(\rightarrow\) \(\bf{x_1 = -5}\) 是一个局部 \(\textbf{最小值}\)。
(2) \(f''(x_2) = 3 \times (2)² - 2 \times 2 - 22 \lt 0\) \(\rightarrow\) \(\bf{x_2 = 2}\) 是一个局部 \(\textbf{最大值}\)。
(3) \(f''(x_3) = 3 \times (4)² - 2 \times 4 - 22 \gt 0\) \(\rightarrow\) \(\bf{x_3 = 4}\) 是一个局部 \(\textbf{最小值}\)。
单峰函数
让我们考虑一个特殊的函数族,它使得优化任务更容易:
一个函数 \(f:\mathbb{R}\to \mathbb{R}\) 在区间 \([a,b]\) 上是单峰的,如果这个函数在该区间 \([a,b]\) 上有一个唯一的(全局)最小值。
更严格地说,一个一维函数 \(f: S\to\mathbb{R}\),如果在区间 \([a,b]\) 上存在唯一的 \(\bf{x}^* \in [a, b]\) 使得 \(f(\bf{x}^*)\) 是 \([a, b]\) 中的最小值,并且对于所有 \(x_1, x_2 \in [a, b]\) 且 \(x_1 \lt x_2\),以下两个性质成立,则称该函数在区间 \([a, b]\) 上是单峰的:
区间上单峰函数的一些例子:
-
\(f(x) = x²\) 在区间 \([-1,1]\) 上是单峰的。
-
\(f(x) = \begin{cases} x, \text{ for } x \geq 0, \\ 0, \text{ for } x < 0 \end{cases}\) 在 \([-1,1]\) 上不是单峰的,因为全局最小值不是唯一的。这是一个凸函数但不是单峰函数的例子。
-
\(f(x) = \begin{cases} x, \text{ for } x > 0, \\ -100, \text{ for } x = 0,\\ 0 \text{ for } x < 0\end{cases}\) 在 \([-1,1]\) 上不是单峰的。它在 \(x=0\) 处有一个唯一的最小值,但当你从 \(-1\) 移动到 \(0\) 时,它并不持续减少(即单调减少)。
-
\(f(x) = cos(x)\) 在区间 \([-\pi/2, 2\pi]\) 上不是单峰的,因为它在 \([-\pi/2, 0]\) 上是增加的。
为了简化,我们将考虑我们的目标函数是单峰的,因为它保证了我们有一个唯一的解来最小化问题。
注意到,给定一个单峰函数 \(f\) 和一个域 \([a, b]\),我们可以将 \([a, b]\) 划分为 \([x_1, x_2, x_4, x_3]\),其中 \(x_1 = a, x_3 = b\),且 \(x_2 - x_1 = x_4 - x_2 = x_3 - x_4\)。然后我们可以很容易地验证,如果 \(f_2 = f(x_2) \lt f(x_4) = f_4\),则极小值 \(x^* \in [x_1, x_4]\)。同样,如果 \(f_2 = f(x_2) \gt f(x_4) = f_4\),则极小值 \(x^* \in [x_2, x_3]\)。因此,我们可以递归地对较小的区间应用这种“划分”过程,直到收敛到最小值。请注意,这种方法与求根时的二分法类似。下面是这种想法的演示图:

然而,请注意,这种方法通常需要每迭代一次进行 2 次新的函数评估。让我们看看黄金分割搜索如何改进这个算法,使其每步只需要进行一次函数评估。
黄金分割搜索(一维)
受上述算法的启发,我们定义了一种用于寻找函数最小值的 区间缩减 方法。与二分法(用于求根)类似,我们在二分法中缩减区间,使得缩减后的区间始终包含根,在 黄金分割搜索 中,我们缩减区间,使得区间始终在我们的域中有一个唯一的极小值。
算法用于寻找 \(f: [a, b] \to \mathbb{R}\) 的最小值:
我们的目标是引入“内部”点 \(x_1\) 和 \(x_2\),并将域缩减到 \([x_1, x_2]\) 以便:
-
如果 \(f(x_1) > f(x_2)\),则我们的新区间将是 \([x_1, b]\)
-
如果 \(f(x_1) \leq f(x_2)\),则我们的新区间将是 \([a, x_2]\)
由于我们不希望每步进行两次函数评估,我们需要确保在下一步:
-
如果输入域是 \([a, x_2]\),则重用 \(x_1\) 作为 2 个新的“内部”点之一,因为它位于 \([a, x_2]\) 之间,并且 \(f(x_1)\) 已经被评估过。
-
类似地,如果输入域是 \([x_1, b]\),则重用 \(x_2\) 作为 2 个新的“内部”点之一,因为它位于 \([x_1, b]\) 之间,并且 \(f(x_2)\) 已经被评估过。
设置 \(h_0 = b - a\) 和 \(h_1 = b - x_1 = x_2 - a\).
由于我们希望确保要检查的区间以一致的速度“缩小”,我们需要一个常数 \(\tau\),使得 \(h_1 = \tau h_0\)(或者更一般地,对于所有 \(k \in \mathbb{N}\),\(h_{k+1} = \tau h_k\))。
由于我们希望“重用” \(x_1\) 或 \(x_2\),它必须满足 \(\tau h_1 = (1 - \tau)h_0\)(您可以使用上面的演示图来验证)。将 \(h_1\) 替换为 \(\tau h_0\),我们得到:
注意到:
由于每次缩减区间时都按固定因子进行,可以观察到该方法 线性收敛:
数字 \(\frac{\sqrt{5}-1}{2}\) 是“黄金比例”的倒数,因此这个算法被称为黄金分割搜索。
在黄金分割搜索中,我们不需要评估 \(f(x)\) 的任何导数。在每次迭代中,我们需要 \(f(x_1)\) 和 \(f(x_2)\),其中 \(x_1\) 或 \(x_2\) 中的一个将与前一次迭代相同,因此每次迭代只需要额外评估 1 个函数(第一次迭代之后)。
示例:黄金分割搜索“区间长度”
考虑在一个单峰函数上运行黄金分割搜索。如果黄金分割搜索从初始区间 \([-10, 10]\) 开始,经过 1 次迭代后新区间的长度是多少?
答案
\((10 - (-10)) \times \tau \approx 12.36\)
牛顿法(一维)
使用泰勒展开,我们可以将函数 \(f\) 在 \(x_0\) 处用二次函数来近似:
我们希望使用一阶必要条件找到二次函数的最小值:
注意,这与牛顿法求解非线性方程 \(f'(x) = 0\) 的步骤相同
我们知道,为了找到局部最小值,我们需要找到函数导数的根。受牛顿法求根的启发,我们定义如下迭代方案:
只要 \(x_k\) 足够接近局部最小值,该方法通常二次收敛。换句话说,牛顿法具有局部收敛性,可能无法收敛,或者收敛到最大值或拐点。
对于一维优化中的牛顿法,我们需要评估 \(f'(x_k)\) 和 \(f''(x_k)\),因此每次迭代需要评估 2 个函数。
示例:一维牛顿法
考虑函数 \(f(x) = 4x³ + 2x² + 5x + 40\)。如果我们使用初始猜测 \(x_0 = 2\),那么经过牛顿法一次迭代后 \(x\) 的值是多少?
答案
要应用牛顿法优化的一步,我们使用迭代公式得到:$$ x_1 = x_0 - \frac{f'(x_0)}{f''(x_0)} $$ 给定函数 $ f(x) = 4x³ + 2x² + 5x + 40 $,其第一导数 $ f'(x) $ 为:$$ f'(x_0) = 12x² + 4x + 5 $$ 因此 $$ f'(2) = 12(2)² + 4(2) + 5 = 12(4) + 8 + 5 = 48 + 8 + 5 = 61 $$ 其第二导数 $ f''(x) $ 为:$$ f''(x) = 24x + 4 $$ 因此 $$ f''(x_0) = 24(2) + 4 = 48 + 4 = 52 $$ 最后,应用牛顿法公式:$$ x_1 = 2 - \frac{61}{52} \approx 0.827 $$
梯度和 Hessian 矩阵的定义
现在我们来修订一些在解决多维优化问题中有用的关键概念:
给定 \(f:\mathbb{R}^n\to \mathbb{R}\),我们定义梯度函数 \(\nabla f: \mathbb{R}^n\to\mathbb{R}^n\) 为:
给定 \(f:\mathbb{R}^n\to \mathbb{R}\),我们定义赫斯矩阵 \({\bf H}_f: \mathbb{R}^n\to\mathbb{R}^{n\times n}\) 为:
解决 N 维优化问题的两种方法
给定一个非线性、连续且光滑的函数 \(f:\;\mathbb{R}^n\to \mathbb{R}\) 以及优化问题 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x \in S}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\),本课程将介绍两种方法:
-
梯度(一阶导数)方法:需要评估 \(f(\boldsymbol{x})\) 和 \(\nabla f(\boldsymbol{x})\) 在集合 \(x \in S\) 中的 \(x\)。特别是,我们将介绍最速下降法。
-
赫斯(二阶导数)方法:需要评估 \(f(\boldsymbol{x})\)、\(\nabla f(\boldsymbol{x})\) 和 \({\nabla}² f(\boldsymbol{x})\) 以及集合 \(x \in S\) 中的 \(x\)。特别是,我们将介绍N 维牛顿法。
其中:
N 维局部最小值的判据
在 n 维优化问题中,我们需要找到一个连续且光滑的函数 \(f:\;\mathbb{R}^n \to \mathbb{R}\) 的最小值。我们可以通过考虑梯度和赫 essian 矩阵的值来判断一个点 \(x^* \in S\) 是否是局部最小值。注意,N-D 梯度等价于 1-D 导数,赫 essian 矩阵在零梯度点的性质如下:
| $ H_f(x^*) $ | $ H_f(x^*) $ 的特征值 | 临界点 $ x^* $ |
|---|---|---|
| 正定 | 所有正值 | 最小值 |
| 负定 | 所有负值 | 最大值 |
| 不定 | 不定 | 鞍点 |
因此,以下是要找到 \(\boldsymbol{x}^*\) 使得 \(f(\boldsymbol{x}^*) = \underset{\boldsymbol{x}}{\mathrm{min}}\hspace{1mm}f(\boldsymbol{x})\) 的条件:
-
必要条件:梯度 \(\nabla f(\boldsymbol{x}^*) = \boldsymbol{0}\)
-
充分条件:梯度 \(\nabla f(\boldsymbol{x}^*) = \boldsymbol{0}\) 且赫 essian 矩阵 \(H_f(\boldsymbol{x^*})\) 是正定的。
示例:找到 N 维函数的所有驻点
考虑以下函数
找到驻点并检查充分条件。
答案
梯度如下:$$ \nabla f(\boldsymbol{x}) = \text{\small gradient} (x) = \begin{bmatrix} 6x_1² - 24 \ 8x_2 + 2 \ \end{bmatrix} $$ 解方程 \(\nabla f = 0 \text{ 得到 }6x_1² - 24 = 0\text{ 和 }8x_2 + 2 = 0\text{,因此 }x_1 = \pm 2 \text{ 和 } x_2 = -0.25\).
赫 essian 矩阵如下:$$ {\bf H}_f(\boldsymbol{x}) = \begin{bmatrix} 12x_1 & 0\ 0 & 8 \ \end{bmatrix} $$ \(\textbf{情况 1:}\)
我们知道我们需要移动的方向以接近最小值,但我们仍然不知道我们需要移动多少距离才能接近最小值。我们需要在最速下降方向中进行“线性搜索”。如果 \(\boldsymbol{x_k}\) 是我们之前的位置,那么我们通过将其移动到负梯度的方向来选择下一个猜测:
下一个问题将是找到 \(\boldsymbol{\alpha}\),我们使用一维优化算法来找到所需的 \(\boldsymbol{\alpha}\)。对于当前的 \(\boldsymbol{x_k}\),以下方程定义了 \(\boldsymbol{\alpha_k}\),这是将 \(\boldsymbol{x_{k+1}}\) 带到线性搜索中的最小点的最优 \(\boldsymbol{\alpha}\) 选择:
因此,在每次迭代中我们计算:
最速下降算法可以形式化为:
-
初始猜测:\(\bf{x_0}\)
-
评估最速下降:\(\bf{s_k = -\nabla f(x_k)}\)
-
执行线性搜索以获得 \(\alpha _k\)(例如,黄金分割搜索):\(\alpha_k = \underset{\alpha}{\mathrm{argmin}} f(\bf{x_k} + \alpha \bf{s_k})\)
-
更新:\(\bf{x_{k+1} = x_k + \alpha _k s_k}\)
通常,最速下降方法线性收敛。
将此算法翻译成 Python:
import numpy.linalg as la
import scipy.optimize as opt
import numpy as np
def obj_func(alpha, x, s):
# code for computing the objective function at (x+alpha*s)
return f_of_x_plus_alpha_s
def gradient(x):
# code for computing gradient
return grad_x
def steepest_descent(x_init):
x_new = x_init
x_prev = np.random.randn(x_init.shape[0])
while(la.norm(x_prev - x_new) > 1e-6):
x_prev = x_new
s = -gradient(x_prev)
alpha = opt.minimize_scalar(obj_func, args=(x_prev, s)).x
x_new = x_prev + alpha*s
return x_new
侧记:观察 \(x_{k+1} = \bf{x_k} - \alpha _k \nabla f(x_k)\),因此 \(\frac{dx_{k+1}}{d\alpha} = -\nabla f(x_k)\)。由于 \(\alpha_k = \underset{\alpha}{\mathrm{argmin}} f(\bf{x_k} + \alpha \bf{s_k})\),线性搜索的一个必要条件是 \(\frac{df}{d\alpha} = 0\)。然后根据链式法则:
因此 \(\nabla f(x_{k+1})\) 与 \(\nabla f(x_k)\) 正交。
示例:最速下降方向
考虑函数 \(f(x_1, x_2) = 10(x_1)³ - (x_2)² + x_1 - 1\)。在起始猜测 \(x_1 = 2, x_2 = 2\) 时,最速下降方向是什么?
答案
示例:最速下降迭代
考虑函数 \(f(x_1, x_2) = (x_1 - 1)² + (x_2 - 1)²\)。在起始猜测 \(y_0 = \begin{bmatrix} 3 \\ 3 \end{bmatrix}^T\) 处的最速下降方向是什么?如果我们选择 \(\alpha_0 = 1\),\(y_1\) 将会是什么?
答案
示例:步长大小
考虑相同的函数 \(f(x_1, x_2) = (x_1 - 1)² + (x_2 - 1)²\) 和初始猜测 \(y_0 = \begin{bmatrix} 3 \\ 3 \end{bmatrix}^T\)。现在给出了这个函数的等高线图可视化。\(\alpha\)的理想选择是什么?

答案
从等高线图中观察,\(f\) 在 \(\begin{bmatrix} 1 \\ 1 \end{bmatrix}\) 处有一个局部最小值。回忆一下上一个问题,\(\nabla f(\bf{y_0}) = \begin{bmatrix} -4 \\ -4 \end{bmatrix}\)
很明显,当 \(\alpha = 0.5\) 时,$$ \bf{y_1} = \begin{bmatrix} 3 \ 3 \end{bmatrix} - 0.5 \times \begin{bmatrix} 4 \ 4 \end{bmatrix} = \begin{bmatrix} 1 \ 1 \end{bmatrix} $$ 因此,当 \(\bf{\alpha = 0.5}\) 时,最速下降算法在恰好 1 次迭代后收敛到最小值。
牛顿法(N 维)
\(n\) 维牛顿法与 \(n\) 维根查找的牛顿法类似,只是我们将 \(n\) 维函数替换为梯度,将雅可比矩阵替换为海森矩阵。我们可以通过考虑函数的泰勒展开来得到结果。
我们求解 \(\nabla \hat{f}(\boldsymbol{s}) = \boldsymbol{0}\) 对于 \(\boldsymbol{s}\)。因此,方程可以翻译为:
这变成了一组线性方程,我们需要求解牛顿步 \(\boldsymbol{s}\)。
优化中 N 维牛顿法的步骤可以形式化描述如下:
-
初始猜测:\(\boldsymbol{x_0}\)
-
求解:\({\bf H}_f(\boldsymbol{x_k})\boldsymbol{s_k} = -\nabla f(\boldsymbol{x_k})\)
-
更新:\(\bf{x_{k+1}} = \bf{x_k} + \bf{s_k}\)
注意,Hessian 与曲率有关,因此包含有关步长应该多大的信息。
该算法的一些性质:
-
在正常情况下,具有二次收敛性。
-
需要二阶导数 L。
-
局部收敛(需要起始猜测接近解)。
-
当 Hessian 矩阵接近不定时,表现不佳。
-
每次迭代的成本:\(O(n³)\)。
该算法可以表示为以下 Python 函数:
import numpy as np
import numpy.linalg as la
def hessian(x):
# Computes the hessian matrix corresponding the given objective function
return hessian_matrix_at_x
def gradient(x):
# Computes the gradient vector corresponding the given objective function
return gradient_vector_at_x
def newtons_method(x_init):
x_new = x_init
x_prev = np.random.randn(x_init.shape[0])
while(la.norm(x_prev-x_new)>1e-6):
x_prev = x_new
s = -la.solve(hessian(x_prev), gradient(x_prev))
x_new = x_prev + s
return x_new
示例:N 维优化中牛顿法的单步
要找到函数 \(f(x, y) = 3x² +2y²\) 的最小值,牛顿法的一步表达式是什么?
答案
函数 $ f(x, y) $ 的梯度由以下给出:$$ \nabla f(x, y) = \begin{bmatrix} \frac{\partial f}{\partial x} \ \frac{\partial f}{\partial y} \end{bmatrix} $$ 并且函数 $ f(x, y) $ 的 Hessian 矩阵由以下给出:$$ H_f(x, y) = \begin{bmatrix} \frac{\partial² f}{\partial x²} & \frac{\partial² f}{\partial x \partial y} \ \frac{\partial² f}{\partial y \partial x} & \frac{\partial² f}{\partial y²} \end{bmatrix} $$ N 维优化的牛顿算法的求解步骤为:$$ Hf(x_k, y_k)\boldsymbol{s_k} = -\nabla f(x, y_{k})$$ 这在数学上等同于:$${\bf{s_k}} = - H_f(x_k, y_k)^{-1} \nabla f(x_k, y_k) $$ 因此,N 维优化的牛顿算法的更新步骤为:$$ \begin{bmatrix} x{k+1} \ y \end{bmatrix} = \begin{bmatrix} x_k \ y_k \end{bmatrix} - H_f(x_k, y_k)^{-1} \nabla f(x_k, y_k) $$ 给定函数 $ f(x, y) = 3x² + 2y² $,其梯度 $ \nabla f(x_k, y_k) $ 和 Hessian 矩阵 $ H_f(x_k, y_k) $ 为:$$ \nabla f(x_k, y_k) = \begin{bmatrix} \frac{\partial f}{\partial x_k} \ \frac{\partial f}{\partial y_k} \end{bmatrix} = \begin{bmatrix} 6x_k \ 4y_k \end{bmatrix} $$ $$ H_f(x_k, y_k) = \begin{bmatrix} \frac{\partial² f}{\partial {x_k}²} & \frac{\partial² f}{\partial x_k \partial y_k} \ \frac{\partial² f}{\partial y_k \partial x_k} & \frac{\partial² f}{\partial {y_k}²} \end{bmatrix} = \begin{bmatrix} 6 & 0 \ 0 & 4 \end{bmatrix} $$ 因此,答案是:$$ \begin{bmatrix} x{k+1} \ y \end{bmatrix} = \begin{bmatrix} x_k \ y_k \end{bmatrix} - {\begin{bmatrix} 6 & 0 \ 0 & 4 \end{bmatrix}}^{-1} \begin{bmatrix} 6x_k \ 4y_k \end{bmatrix} $$
示例:N 维优化中牛顿法的收敛性
当使用牛顿法寻找函数 \(f(x, y) = 0.5x² +2.5y²\) 的最小值时,估计收敛所需的迭代次数?
答案
答案:\(\textbf{1}\)。
原因:注意到 N 维优化中的牛顿法是从截断到二次项的泰勒级数推导出来的(即,\(\frac{1}{2}s^T {\bf H}\_f(\boldsymbol{x})s\))。这意味着它对二次函数是准确的。
复习问题
-
一维中,一个点成为局部最小值的必要和充分条件是什么?
-
在 \({n}\) 维度中,一个点成为局部最小值的必要和充分条件是什么?
-
如何将极值分类为最小值、最大值或鞍点?
-
局部最小值和全局最小值之间有什么区别?
-
函数单峰意味着什么?
-
函数需要具备哪些特殊属性,才能使黄金分割搜索找到最小值?
-
执行一次黄金分割搜索的迭代。
-
计算函数的梯度(函数有多个输入,一个输出)
-
计算函数的雅可比矩阵(函数有多个输入,多个输出)。
-
计算函数的海森矩阵。
-
在最速下降/梯度下降中找到搜索方向。
-
为什么梯度下降的每一步都必须执行线搜索?
-
在一维中执行牛顿法的一次迭代。
-
在 \({n}\) 维度中执行牛顿法的一次迭代。
-
牛顿法何时无法收敛到最小值?
-
黄金分割搜索每次迭代需要执行哪些操作?
-
在一维中,牛顿法每次迭代需要执行哪些操作?
-
在 \({n}\) 维度中,牛顿法每次迭代需要执行哪些操作?
-
牛顿法的收敛速度是多少?
更新日志
-
2025 年 11 月 12 日:Dev Singh (dsingh14) — 修复代码片段
-
2024 年 10 月 31 日:Dev Singh (dsingh14) — 修复梯度计算
-
2024 年 3 月 17 日:Kaiyao Ke (kaiyaok2) — 调整笔记顺序
查看剩余条目
+ 2024 年 3 月 1 日:Kaiyao Ke (kaiyaok2) — 将笔记与幻灯片对齐,添加示例并重构现有笔记
+ 2020 年 8 月 8 日:Jerry Yang (jiayiy7) — 添加单峰示例
+ 2020 年 4 月 26 日:Mariana Silva (mfsilva) — 小幅度文本修订
+ 2018 年 4 月 25 日:Adam Stewart (adamjs5) — 修复 `newtons_method` 中缺失的括号
+ 2017 年 11 月 25 日:Adam Stewart (adamjs5) — 修复海森矩阵中缺失的偏导数
+ 2017 年 11 月 20 日:Erin Carrier (ecarrie2) — 删除 Gauss-Newton/LM,全文小幅度修改和调整
+ 2017 年 11 月 20 日:Nate Bowman (nlbowma2) — 添加复习问题
+ 2017 年 11 月 20 日:Kaushik Kulkarni (kgk2) — 修复表格格式
+ 2017 年 10 月 25 日:Arun Lakshmanan (lakshma2) — 第一份完整草案
+ 2017 年 10 月 25 日:Kaushik Kulkarni (kgk2) — 第一份完整草案
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概述
作者
- CS 357 课程工作人员
最小二乘拟合
原文:
cs357.cs.illinois.edu/textbook/notes/linear-least-squares.html
学习目标
-
从一组数据中建立一个线性最小二乘问题
-
使用奇异值分解来解决最小二乘问题
-
量化最小二乘问题中的误差
基于一组数据的线性回归
给定 \(m\) 个数据点(其中 \(m>2\)),\(\{(t_1,y_1),(t_2,y_2),\dots,(t_m,y_m)\}\),我们想要找到一条最佳拟合这些数据点的直线。从数学上讲,我们正在寻找 \(x_0\) 和 \(x_1\),使得
以矩阵形式,得到的线性系统为:
其中 \({\bf A}\) 是一个 \(m\times n\) 矩阵,\({\bf x}\) 是一个 \(n\times 1\) 矩阵,\({\bf b}\) 是一个 \(m\times 1\) 矩阵。
理想情况下,我们想要找到 \({\bf A}\) 的列的适当线性组合,以构成向量 \({\bf b}\)。如果存在一个满足 \({\bf A x} = {\bf b}\) 的解,那么 \({\bf b} \in range({\bf A})\)。
然而,在这个线性方程组系统中,我们拥有的方程比未知数多,通常上述问题没有精确的解。
当 $ m>n$ 时,我们称这个线性系统为 超定 的,并且 \({\bf A x} = {\bf b}\) 的等式通常不能精确满足,因为 \({\bf b}\) 可能不在 \({\bf A}\) 的列空间中。
因此,超定系统最好写成
线性最小二乘问题
对于一个超定系统 \({\bf A x}\cong {\bf b}\),我们通常寻找一个解 \({\bf x}\),使得残差向量 \({\bf r} = {\bf b} - {\bf A} {\bf x}\) 的欧几里得范数最小,
这个问题 \(A {\bf x} \cong {\bf b}\) 被称为 线性最小二乘问题,其解 \({\bf x}\) 被称为 最小二乘解。 \({\bf A}\) 是一个 \({m \times n}\) 矩阵,其中 \({m \ge n}\),\({m}\) 是数据对点数,\({n}\) 是“最佳拟合”函数的参数数。线性最小二乘问题 \(A {\bf x} \cong {\bf b}\) 总是 有解。当且仅当 \({rank({\bf A})= n}\) 时,这个解是唯一的。
正则方程
考虑最小二乘问题 \({\bf A} {\bf x} \cong {\bf b}\),其中 ${\bf A} $ 是 \(m \times n\) 的实矩阵(\(m > n\))。如上所述,最小二乘解最小化了残差的平方 2-范数。因此,我们想要找到使以下函数最小的 \(\mathbf{x}\):
为了解决这个无约束最小化问题,我们需要满足一阶必要条件以获得驻点:
得到的平方(\(n \times n\))线性系统
被称为正则方程组。如果矩阵 \({\bf A}\) 是满秩的,则最小二乘解是唯一的,并且由以下给出:
我们可以通过评估 \(\phi\) 的 Hessian 来查看最小化问题的二阶充分条件:
由于 Hessian 矩阵是对称和正定的,我们确认最小二乘解 \({\bf x}\) 确实是一个最小值点。
尽管对于满秩矩阵,可以通过正则方程解决最小二乘问题,但解往往会恶化问题的条件。具体来说,
由于这个原因,使用正则方程来找到最小二乘解通常不是一个好的选择(尽管实现起来很简单)。
解决线性最小二乘的另一种方法是找到 \({\bf y} = {\bf A} {\bf x}\),它是最接近向量 \({\bf b}\) 的。当残差 \({\bf r} = {\bf b} - {\bf y} = {\bf b} - {\bf A} {\bf x}\) 与 \({\bf A}\) 的所有列正交时,则 \({\bf y}\) 是最接近 \({\bf b}\) 的。
数据拟合与插值
重要的是要理解,插值和最小二乘数据拟合,尽管在某些方面相似,但它们的目的是根本不同的。在这两个问题中,我们都有一个数据点集 \((t_i, y_i)\),\(i=1,\ldots,m\),并且我们试图确定基函数线性组合的系数。
通过插值,我们寻找基函数的线性组合,使得所得函数能够精确地通过每个数据点。因此,对于 \(m\) 个独特的数据点,我们需要 \(m\) 个线性无关的基函数(并且由此产生的线性系统将是方阵且满秩,因此它将有一个精确的解)。
相反,然而,在最小二乘数据拟合中,我们有一些模型,我们试图找到最佳拟合数据点的模型参数。例如,在线性最小二乘中,我们可能有 300 个有噪声的数据点,我们希望将其建模为二次函数。因此,我们试图将我们的数据表示为
其中 \(x_0, x_1,\) 和 \(x_2\) 是我们想要确定的未知数(基函数的系数)。由于数据点比参数多得多,我们并不期望函数会精确地通过数据点。对于这个例子,在有噪声的数据点上,我们不希望函数精确地通过数据点,因为我们正在试图模拟一般趋势而不是捕捉噪声。
计算复杂度
由于正则方程组产生一个平方对称矩阵,最小二乘解可以使用如 Cholesky 分解等有效方法来计算。请注意,分解的整体计算复杂度是 \(\mathcal{O}(n³)\)。然而,矩阵 \({\bf A} ^T {\bf A}\) 的构建复杂度是 \(\mathcal{O}(mn²)\)。
在典型的数据拟合问题中,\(m >> n\),因此正则方程法的时间复杂度总体上是 \({\bf \mathcal{O}(mn²)}\).
使用奇异值分解(SVD)求解最小二乘问题
解决最小二乘问题 \({\bf A} {\bf x} \cong {\bf b}\)(其中我们寻找 \({\bf x}\) 以最小化 \(\|{\bf b} - {\bf A} {\bf x}\|_2²\))的另一种方法是使用 \({\bf A}\) 的奇异值分解(SVD)。
其中残差的平方范数变为:
我们可以从(1)到(2)进行转换,因为乘以一个正交矩阵不会改变向量的 2-范数。现在,让
我们现在正在寻找 \({\bf y}\) 以最小化
注意到
因此我们选择
这将最小化 \(\|{\bf z} - {\bf \Sigma} {\bf y}\|_2²\). 最后,我们计算
为了找到 \({\bf x}\)。最小二乘解的表达式是
其中 \({\bf u}_i\) 表示 \({\bf U}\) 的第 \(i\) 列,\({\bf v}_i\) 表示 \({\bf V}\) 的第 \(i\) 列。
在闭式表达中,我们可以将最小二乘解表示为:
其中 \({\bf \Sigma}^{+}\) 是通过取非零对角元素的倒数,保留零,并转置结果矩阵计算出的奇异矩阵的伪逆。例如:
或者以简化的形式:
使用简化 SVD 的计算复杂度
使用给定的简化 SVD 求解最小二乘问题的时间复杂度为 \(\mathcal{O}(mn)\)。
假设我们事先知道 \(\bf A\) 的简化奇异值分解(这意味着我们事先知道 \(\bf V, \Sigma^{+}_{R}, U^{T}_{R}\) 的元素)。
然后,使用 \(n \times m\) 矩阵 \(\bf U^{T}_{R}\) 和 \(m \times 1\) 向量 \(\bf b\) 求解 \(\bf z = U^{T}_{R}b\) 的复杂度为 \(\mathcal{O}(mn)\)。
使用 \(n \times n\) 矩阵 \(\bf \Sigma^{+}_{R}\) 和 \(n \times 1\) 向量 \(\bf z\) 求解 \(\bf y = \Sigma^{+}_{R}z\) 的复杂度为 \(\mathcal{O}(n)\),因为 \(\bf \Sigma^{+}_{R}\) 是一个对角矩阵。
使用 \(n \times n\) 矩阵 \(\bf V\) 和 \(n \times 1\) 向量 \(\bf y\) 求解 \(\bf x = Vy\) 的复杂度为 \(\mathcal{O}(n²)\)。
因此,时间复杂度为 \(\mathcal{O}(n² + n + mn) = \mathcal{O}(mn)\),因为 \(m > n\)。我们只有在事先知道 \(\bf A\) 的简化奇异值分解的情况下才能实现这一点。
使用 SVD 确定最小二乘问题中的残差
我们已经展示了如何使用 SVD 来找到最小二乘问题的最小二乘解(即最小化残差平方 2-范数的解)\({\bf A} {\bf x} \cong {\bf b}\)。我们还可以使用 SVD 来确定残差值的最小二乘解的精确表达式。
假设在 \({\bf A}\) 的奇异值分解中,\({\bf A} = {\bf U \Sigma V}^T\),\({\bf \Sigma}\) 的对角线元素按降序排列($\sigma_1 \ge \sigma_2 \ge \dots $),并且 \({\bf \Sigma}\) 的前 \(r\) 个对角线元素非零,其余为零,那么
回想一下
我们得到
\({\bf u}_i\) 表示 \({\bf U}\) 的第 \(i\) 列。
(更多正式的证明请查看这个视频)
使用 SVD 求解最小二乘解的示例
假设我们有 \(3\) 个数据点,\({(t_i,y_i)}={(1,1.2),(2,1.9),(3,1)}\),我们想要找到最佳拟合这些数据点的直线,\({y = x_0 + x_1 t}\) 的系数。使用 SVD 求解这个最小二乘问题的代码如下:
import numpy as np
import numpy.linalg as la
A = np.array([[1,1],[2,1],[3,1]])
b = np.array([1.2,1.9,1])
U, s, V = la.svd(A)
V = V.T
y = np.zeros(len(A[0]))
z = np.dot(U.T,b)
k = 0
threshold = 0.01
# matrix multiplying A by pseudo-inverse of sigma while k < len(A[0]) and s[k] > threshold:
y[k] = z[k]/s[k]
k += 1
x = np.dot(V,y)
print("The function of the best line is: y = " + str(x[0]) + "x + " + str(x[1]))
非线性最小二乘问题与线性最小二乘问题比较
上述线性最小二乘问题与一个超定线性系统 \(A {\bf x} \cong {\bf b}\) 相关联。这个问题被称为“线性”,因为我们正在寻找的拟合函数在 \({\bf x}\) 的分量上是线性的。例如,如果我们正在寻找一个多项式拟合函数
来拟合数据点 \({(t_i,y_i), i = 1, …, m}\)(其中 \(m > n\)),这个问题可以使用线性最小二乘法来解决,因为 \(f(t,{\bf x})\) 在 \({\bf x}\) 的分量上是线性的(尽管 \(f(t,{\bf x})\) 在 \(t\) 上是非线性的)。
如果数据点 \((t_i,y_i), i = 1, ..., m\) 的拟合函数 \(f(t,{\bf x})\) 在 \({\bf x}\) 的分量上是非线性的,那么这个问题就是一个非线性最小二乘问题。例如,拟合指数和
是一个非线性最小二乘问题。
线性最小二乘问题有闭式解,而非线性最小二乘问题没有闭式解,需要使用数值方法来求解。
复习问题
-
最小二乘解最小化什么值?
-
对于给定的模型和给定的数据点,你能形成最小二乘问题 \({\bf A x} \cong {\bf b}\) 的系统吗?
-
对于一个小问题,给定一些数据点和模型,你能确定最小二乘解吗?
-
通常,我们可以对最小二乘解的残差值说些什么?
-
最小二乘数据拟合和插值之间有什么区别?
-
给定矩阵 \({\bf A}\) 的奇异值分解(SVD),我们如何使用 SVD 来计算最小二乘解的残差?
-
给定矩阵 \({\bf A}\) 的奇异值分解(SVD),我们如何使用 SVD 来计算最小二乘解?对于一个小问题,能够做到这一点。
-
给定一个矩阵 \({\bf A}\) 的已计算奇异值分解(SVD),使用 SVD 求解最小二乘问题的成本是多少?
-
为什么你会使用奇异值分解(SVD)而不是正则方程来找到 \({\bf A x} \cong {\bf b}\) 的解?
-
通过正则方程求解最小二乘问题或使用奇异值分解(SVD)求解最小二乘问题哪个成本更低?
-
线性最小二乘问题和非线性最小二乘问题有什么区别?什么类型的模型使其成为非线性问题?对于数据点 \({\left(t_i, y_i\right)}\),如果我们尝试拟合 \({y = a*cos(t) + b}\)(其中 \({a}\) 和 \({b}\) 是我们试图确定的系数),这是一个线性还是非线性最小二乘问题?
更新日志
-
2024 年 3 月 6 日:Bhargav Chandaka (bhargav9) — 对内容进行重大重组,以与幻灯片/视频中的内容相匹配
-
2023 年 4 月 28 日:Yuxuan Chen (yuxuan19) — 添加使用降秩 SVD 的计算复杂度
-
2022 年 4 月 9 日:Arnav Shah (arnavss2) — 在作业中添加了关于幻灯片的一些评论
查看剩余条目
+ 2020 年 8 月 8 日:Jerry Yang (jiayiy7) — 添加了解决最小二乘法使用奇异值分解的正式证明链接
+ 2020 年 4 月 26 日:Mariana Silva (mfsilva) — 全面改进了文本;移除了非线性最小二乘法的理论
+ 2018 年 11 月 14 日:Erin Carrier (ecarrie2) — 修复了 lstsq 结果求和范围中的错误
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 移除了演示链接
+ 2017 年 11 月 29 日:Erin Carrier (ecarrie2) — 修复了 lst-sq 代码中的错误,非线性 lst-sq 中的雅可比描述
+ 2017 年 11 月 17 日:Erin Carrier (ecarrie2) — 修复了错误的链接
+ 2017 年 11 月 16 日:Erin Carrier (ecarrie2) — 添加了复习问题,对全文进行了细微的格式调整以确保一致性,增加了正常方程和插值与列表平方法部分,从非线性最小二乘法中移除了高斯-牛顿法
+ 2017 年 11 月 12 日:Yu Meng (yumeng5) — 首次完整草案
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概要
作者
- CS 357 课程工作人员
奇异值分解 (SVD)
学习目标
-
构建矩阵的奇异值分解
-
识别奇异值分解的各个部分
-
使用奇异值分解解决问题
概述
在之前,我们探索了一类方向由矩阵保持不变的向量。我们发现,对于任何 方阵,如果存在 \(n\) 个线性无关的特征向量,我们就可以将 \(\bf A\) 对角化为 \(\bf{AX = XD}\) 的形式,其中 \(\bf X\) 是 \(\mathbb{R}^n\) 的一个基,其中 \(\bf{Ax_i = \lambda_ix_i}\)。
对于 任何 \(m \times n\) 矩阵,都存在一个形式为 \(\bf{AV = U{\Sigma}}\) 或 \(\bf{A=U{\Sigma}V^T}\) 的奇异值分解。为了得到这种组合,我们需要 \(\bf U\) 作为 \(\mathbb{R}^m\) 的正交基,\(\bf V\) 作为 \(\mathbb{R}^n\) 的正交基,\(\bf{\Sigma}\) 作为 \(m \times n\) 的对角矩阵,其中 \(\bf{Av_i = \sigma_iu_i}\)。
-
\(\bf U\) 由 \(\bf{AA^T}\) 的特征向量作为其列组成。
-
\(\bf V\) 由 \(\bf{A^TA}\) 的特征向量作为其列组成。
-
\(\bf \Sigma\) 是一个对角矩阵,由 \(\bf{A^TA}\)(或 \(\bf{AA^T}\))的特征值的平方根组成,称为奇异值。
- \(\bf{A^TA}\) 和 \(\bf{AA^T}\) 有相同的正特征值,因此特征值的平方根也是相同的。1
-
\(\bf \Sigma\) 的对角线按非递增的奇异值排序,而 \(\bf U\) 和 \(\bf V\) 的列分别按顺序排列。
此外,我们定义一个简化的形式:\({\bf A} = {\bf U_{R}} {\bf \Sigma_{R}} {\bf V_R}^T\),其中 \({\bf U_R}\) 是一个 \(m \times k\) 矩阵,\({\bf V_R}\) 是一个 \(n \times k\) 矩阵,\({\bf \Sigma_{R}}\) 是一个 \(k \times k\) 的对角矩阵。在这里,\(k = \min(m,n)\)。
这些命题的证明如下:
奇异值分解
一个 \(m \times n\) 的实矩阵 \({\bf A}\) 有如下形式的奇异值分解
其中 \({\bf U}\) 是一个 \(m \times m\) 的正交矩阵,\({\bf V}\) 是一个 \(n \times n\) 的正交矩阵,\({\bf \Sigma}\) 是一个 \(m \times n\) 的对角矩阵。具体来说,
- \({\bf U}\) 是一个 \(m \times m\) 的正交矩阵,其列是 \({\bf A} {\bf A}^T\) 的特征向量,称为 \({\bf A}\) 的 左奇异向量。
因此,\(\bf{AA^T=U\Sigma²U^T}\),这是一个对角化,其中 \(\bf U\) 的列是线性无关的。
- \({\bf V}\) 是一个 \(n \times n\) 的正交矩阵,其列是 \({\bf A}^T {\bf A}\) 的特征向量,称为 \({\bf A}\) 的 右奇异向量。
因此,\(\bf{A^TA=V\Sigma²V^T}\),这是一个对角化,其中 V 的列是线性无关的。
- \({\bf \Sigma}\) 是一个 \(m \times n\) 的对角矩阵,由 \(A^TA\) 的特征值的平方根组成,形式如下:
其中 \(k = \min(m,n)\) 且 \(\sigma_1 \ge \sigma_2 \dots \ge \sigma_s \ge 0\)。对角线元素被称为 \({\bf A}\) 的奇异值。
获取奇异值
注意到矩阵 \(\bf{A^TA}\) 和 \(\bf{AA^T}\) 总是具有相同的非零特征值。此外,它们都是正半定矩阵(定义:\(\mathbf{x^{T}Bx} \geq 0 \quad \forall \mathbf{x} \neq 0\))。由于正半定矩阵的特征值总是非负的,奇异值总是非负的。
如果 \(\mathbf{A}^T\mathbf{x} \ne 0\),那么 \(\mathbf{A}^T\mathbf{A}\) 和 \(\mathbf{A}\mathbf{A}^T\) 都具有相同的特征值:
时间复杂度
计算任意 \(m \times n\) 矩阵的奇异值分解的时间复杂度是 \(\alpha (m²n + n³)\),其中常数 \(\alpha\) 的范围从 4 到 10(或更多),具体取决于算法。
通常,我们可以将成本定义为:\(\mathcal{O}(m²n + n³)\)

降秩奇异值分解
非方阵 \({\bf A}\)(大小为 \(m \times n\))的奇异值分解可以用降秩格式表示:
-
对于 \(m \ge n\):\({\bf U}\) 是 \(m \times n\),\({\bf \Sigma}\) 是 \(n \times n\),\({\bf V}\) 是 \(n \times n\)
-
对于 \(m \le n\):\({\bf U}\) 是 \(m \times m\),\({\bf \Sigma}\) 是 \(m \times m\),\({\bf V}\) 是 \(n \times m\)(注意如果 \({\bf V}\) 是 \(n \times m\),那么 \({\bf V}^T\) 是 \(m \times n\))
以下图展示了降秩奇异值分解(红色)与完整奇异值分解(灰色)的对比。

通常,我们将降秩奇异值分解表示为:
其中 \({\bf U}_R\) 是一个 \(m \times k\) 矩阵,\({\bf V}_R\) 是一个 \(n \times k\) 矩阵,\({\bf \Sigma}_R\) 是一个 \(k \times k\) 矩阵,且 \(k = \min(m,n)\)。
示例:计算奇异值分解
我们从以下非方阵 \({\bf A}\) 开始
我们将计算 SVD 的缩减形式(这里 \(s = 3\)):
(1) 计算 \({\bf A}^T {\bf A}\):
(2) 计算 \({\bf A}^T {\bf A}\) 的特征向量和特征值:
(3) 从 \({\bf A}^T {\bf A}\) 的特征向量构造 \({\bf V}_R\):
(4) 从 \({\bf A}^T {\bf A}\) 的特征值平方根构造 \({\bf \Sigma}_R\):
(5) 通过解 \({\bf U}{\bf\Sigma} = {\bf A}{\bf V}\) 来找到 \({\bf U}\)。对于我们的缩减情况,我们可以找到 \({\bf U}_R = {\bf A}{\bf V}_R {\bf \Sigma}_R^{-1}\)。您也可以通过计算 \({\bf AA}^T\) 的特征向量来找到 \({\bf U}\)。
我们得到了矩阵 \({\bf A}\) 的以下奇异值分解:
回想一下,我们在这里计算了 缩减的 SVD 分解(即 \({\bf \Sigma}\) 是方阵,\({\bf U}\) 是非方阵)。
矩阵的秩、零空间和值域
假设 \({\bf A}\) 是一个 \(m \times n\) 的矩阵,其中 \(m > n\)(不失一般性):
我们可以将上述内容重新写为:
此外,两个矩阵的乘积可以写成外积的和:
对于一个一般的矩形矩阵,我们有:
其中 \(s = \min(m,n)\).
如果 \({\bf A}\) 有 \(s\) 个非零奇异值,则矩阵是满秩的,即 \(\text{rank}({\bf A}) = s\).
如果 \({\bf A}\) 有 \(r\) 个非零奇异值,且 \(r < s\),则矩阵是秩不足的,即 \(\text{rank}({\bf A}) = r\).
换句话说,\({\bf A}\) 的秩等于非零奇异值的数量,这与 \({\bf \Sigma}\) 中非零对角元素的数量相同。
四舍五入误差可能导致秩不足矩阵中出现小但非零的奇异值。小于给定容差的奇异值被认为是数值上等同于零的,这定义了有时被称为有效秩的概念。
与 \({\bf A}\) 的奇异值消失对应的右奇异向量(\({\bf V}\) 的列)张成了 \({\bf A}\) 的零空间,即 null(\({\bf A}\)) = span{\({\bf v}_{r+1}\), \({\bf v}_{r+2}\), …, \({\bf v}_{n}\)}.
与 \({\bf A}\) 的非零奇异值对应的左奇异向量(\({\bf U}\) 的列)张成了 \({\bf A}\) 的值域,即 range(\({\bf A}\)) = span{\({\bf u}_{1}\), \({\bf u}_{2}\), …, \({\bf u}_{r}\)}.
示例:
\({\bf A}\) 的秩是 2。
向量 \(\left[ \begin{array}{c} \frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \\ 0 \\ 0 \end{array} \right]\) 和 \(\left[ \begin{array}{c} -\frac{1}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \\ 0 \\ 0 \end{array} \right]\) 为 \({\bf A}\) 的值域提供了一个正交归一基。
向量 \(\left[ \begin{array}{c} 0 \\ 0\\ 1 \end{array} \right]\) 为 \({\bf A}\) 的零空间的正交基。
(Moore-Penrose) 伪逆
如果矩阵 \({\bf \Sigma}\) 是秩亏的,我们无法得到其逆。我们定义伪逆代替:
对于一个具有已知 SVD (\({\bf A} = {\bf U\Sigma V}^T\)) 的一般非方阵 \({\bf A}\),伪逆定义为:
例如,如果我们考虑一个 \(m \times n\) 的满秩矩阵,其中 \(m > n\):
矩阵的欧几里得范数
矩阵 \({\bf A}\) 的诱导 2-范数可以通过矩阵的奇异值分解(SVD)来获得:
因此,
在上述方程中,所有关于范数 \(\| . \|\) 的符号都指的是 \(p=2\) 的欧几里得范数,并且我们使用了 \({\bf U}\) 和 \({\bf V}\) 是正交矩阵的事实,因此 \(\|{\bf U}\|_2 = \|{\bf V}\|_2 = 1\)。
示例:
我们从以下非方阵 \({\bf A}\) 开始:
从 SVD 分解计算得到的奇异值矩阵 \({\bf \Sigma}\):
因此,\({\bf A}\) 的 2-范数是
矩阵逆的欧几里得范数
按照上述相同的推导方法,我们可以证明对于一个满秩 \(n \times n\) 矩阵,我们有:
其中 \({\sigma_n}\) 是最小的奇异值。
对于非方阵,我们可以使用伪逆的定义(无论其秩如何):
其中 \({\sigma_r}\) 是最小的非零奇异值。注意,对于一个满秩的方阵,我们有 \(\| {\bf A}^{+} \|_2 = \| {\bf A}^{-1} \|_2\)。上述定义的一个例外是零矩阵。在这种情况下,\(\| {\bf A}^{+} \|_2 = 0\)
2-范数条件数
矩阵 \({\bf A}\) 的 2-范数条件数是其最大奇异值与最小奇异值的比:
如果矩阵 \({\bf A}\) 是秩亏缺的,即 \(\text{rank}({\bf A}) < \min(m,n)\),那么 \(\text{cond}_2({\bf A}) = \infty\)。
低秩逼近
对于一个 \(m \times n\) 的矩阵 \({\bf A}\),其中 \(k < s = \min(m,n)\),对于某个矩阵范数 \(\|.\|\),最佳秩-\(k\) 逼近是使以下问题最小化的一个:
在诱导的 \(2\)-范数下,最佳秩-\(k\) 逼近由左和右奇异向量的前 \(k\) 个外积的和给出,这些外积由相应的奇异值缩放(其中,\(\sigma_1 \ge \dots \ge \sigma_s\)):
注意到在诱导的 \(2\)-范数条件下,最佳逼近矩阵与矩阵之间的范数是矩阵的第 \((k+1)^\text{th}\) 个奇异值的模:
注意,最佳秩-\({k}\) 逼近 \({\bf A}\) 可以通过只存储 \({k}\) 个奇异值 \({\sigma_1,\dots,\sigma_k}\),\({k}\) 个左奇异向量 \({\bf u_1,\dots,\bf u_k}\) 和 \({k}\) 个右奇异向量 \({\bf v_1,\dots, \bf v_k}\) 来有效地存储。
下图显示了图像的最佳秩-\(k\) 逼近(你可以在 IPython 笔记本中找到生成这些图像的代码片段):

使用奇异值分解(SVD)求解平方线性方程组
如果 \(\bf A\) 是一个 \(n \times n\) 的平方矩阵,并且我们想求解 \(\bf{Ax=b}\),我们可以使用 A 的奇异值分解:
解:\(\bf{\Sigma y=U^Tb}\)(对角矩阵,容易求解)
评估:\(\bf{x=Vy}\)
-
求解的成本:\(O(n²)\)
-
分解的成本 \(O(n³)\)。回想一下,SVD 和 LU 具有相同的渐近行为,然而 SVD 的操作数——\(n³\) 前的常数因子——更大。
脚注
- 查看 这篇 Math Stack Exchange 帖子 以获得简要说明。
复习问题
-
对于具有 SVD 分解 \(\bf{A=U{\Sigma}V^T}\) 的矩阵 \(\bf A\),\(\bf U\) 的列是什么?我们如何找到它们?\(\bf V\) 的列是什么?我们如何找到它们?\(\bf{\Sigma}\) 的元素是什么?我们如何找到它们?
-
\(\bf U\), \(\bf V\) 和 \(\bf{\Sigma}\) 具有哪些特殊性质?
-
在矩阵的完整 SVD 中,\(\bf U\),\(\bf V\) 和 \(\bf{\Sigma}\) 的形状是什么?
-
在矩阵的简化 SVD 中,\(\bf U\),\(\bf V\) 和 \(\bf{\Sigma}\) 的形状是什么?
-
计算 SVD 的成本是多少?
-
给定一个矩阵 \(\bf A\) 的已计算 SVD,使用 SVD 求解线性系统 \(\bf{Ax=B}\) 的成本是多少?你将如何使用 SVD 来求解这个系统?
-
你如何使用 SVD 来计算矩阵的低秩近似?对于一个小矩阵,你应该能够计算给定的低秩近似(即秩一,秩二)。
-
给定矩阵 \(\bf A\) 的 SVD,\(\mathbf{A}^+\)(\(\bf A\) 的伪逆)的 SVD 是什么?
-
给定矩阵 \(\bf A\) 的 SVD,矩阵的 2-范数是多少?矩阵的 2-范数条件数是多少?
更新日志
-
2024 年 11 月 20 日:Dev Singh (dsingh14) — 添加更多关于奇异值的信息
-
2024 年 4 月 5 日:Pascal Adhikary (pascala2) — 添加/重写概述,证明,求解线性系统
-
2022 年 4 月 10 日:Yuxuan Chen (yuxuan19) — 添加 svd 证明,更改 svd 成本,包含 svd 总结
查看剩余条目
+ 2020 年 4 月 26 日:Mariana Silva (mfsilva) — 为章节添加更多细节
+ 2018 年 11 月 14 日:Erin Carrier (ecarrie2) — 修正拼写错误
+ 2018 年 10 月 18 日:Erin Carrier (ecarrie2) — 修正 svd 成本
+ 2018 年 1 月 14 日:Erin Carrier (ecarrie2) — 删除演示链接
+ 2017 年 12 月 4 日:Arun Lakshmanan (lakshma2) — 修正最佳秩近似,svd 图像
+ 2017 年 11 月 15 日:Erin Carrier (ecarrie2) — 添加复习问题,添加条件数部分,删除正则方程,小幅度修正和澄清
+ 2017 年 11 月 13 日:Arun Lakshmanan (lakshma2) — 第一份完整草案
+ 2017 年 10 月 17 日:Luke Olson (lukeo) — 概述
主成分分析(PCA)
学习目标
-
理解为什么主成分分析是分析数据集的重要工具
-
了解 PCA 的优缺点
-
能够实现 PCA 算法
什么是 PCA?
PCA,或主成分分析,是一种在不丢失重要信息的情况下减少大数据集的算法。PCA被定义为一种正交线性变换,它将数据转换到一个新的坐标系,使得数据通过某个标量投影的最大方差位于第一个坐标(称为第一主成分),第二个最大方差位于第二个坐标,依此类推。
简单来说,它检测最大方差的方向,并将原始数据集投影到一个低维子空间(直到基的变化),该子空间仍然包含大部分重要信息。
-
优点:只省略了“最不重要的”变量,保留了更有价值的变量。此外,创建的新变量是相互独立的,这对于线性模型是必不可少的。
-
缺点:新创建的变量将与原始数据集的含义不同。(解释性丢失)
示例
考虑一个包含 \(m\) 个样本和 30 个不同细胞特征的大的数据集。有许多变量彼此高度相关。我们可以创建一个 $m \times$30 的矩阵 \(\bf A\),其中列 \(\bf F_i\) 代表不同的特征。
现在假设我们想要降低特征空间。一种方法是直接删除一些特征变量。例如,我们可以忽略最后 20 个特征列,以获得一个降低的数据矩阵 \(\bf A^*\)。这种方法简单且保持了特征变量的解释性,但我们已经丢失了删除列的信息。
另一种方法是使用 PCA。我们通过原始变量的特定线性组合创建“新的特征变量”\(\bf F_i^*\)。PCA 之后的所有新变量都是相互独立的。现在,我们能够使用更少的变量,但仍然包含所有特征的信息。这里的缺点是我们已经失去了新特征变量的“有意义的”解释。
数据中心化
主成分分析(PCA)的第一步是数据中心化。我们对数据集 \(\bf A\) 的数据列进行平移,使得每一列的平均值为 0。对于 \(\bf A\) 的每个特征列 \(\bf F_i\),我们计算均值 \(\bar{F_i}\),并从列 \(\bf F_i\) 的每个条目中减去 \(\bar{F_i}\)。我们对每一列执行此过程,直到我们获得一个新的中心化数据集 \(\bf A\)。
示例
这是 2 维坐标空间中 6 个数据点数据中心化的一个例子:
我们首先计算均值点 \(\bar{p} = (4.6, 17.1)\),然后平移所有数据点,使得新的均值点 \(\bar{p}' = (0, 0)\) 位于中心。

协方差矩阵
对于我们中心化的数据集 \(\bf A\),其维度为 \(m \times n\),其中 \(m\) 是数据点的总数,\(n\) 是特征的数目,协方差矩阵被定义为
\(Cov({\bf A})\) 的对角元素解释了每个特征如何与其自身相关,对角元素之和被称为问题的总体变异性(总方差)。
示例
考虑以下形式的协方差矩阵。从这个矩阵中,我们可以得到:
-
\(a_{ii}\) = 每个 \(\bf F_i\) 的方差(\(\bf F_i\) 与其自身的相关性)。这里 \(i = 1, 2, 3\)。
-
\(a_{11} + a_{22} + a_{33}\) = 总体变异性(总方差)。
-
\(\frac{a_{ii}}{a_{11} + a_{22} + a_{33}} \cdot\) 100% = 由 \(\bf F_i\) 解释的总方差百分比。这里 \(i = 1, 2, 3\)。

对角化与主成分
PCA 用新的变量替换原始特征变量,这些新变量称为主成分,它们是正交的(即它们之间没有协方差)并且方差按降序排列。为了实现这一点,我们将使用协方差矩阵的对角化。
这里 \({\bf V}\) 的列是 \({\bf A}^T {\bf A}\) 的特征向量,相应的特征值是对角矩阵 \({\bf D}\) 的对角元素。协方差矩阵的最大特征值对应于数据集的最大方差,相关的特征向量是最大方差的方向,称为第一主成分。
示例
对于上述示例中的相同协方差矩阵,我们可以将其写成对角化形式。在这里,\(\frac{1}{m-1} \cdot (d_{11} + d_{22} + d_{33})\)的总和等于 \(a_{11} + a_{22} + a_{33}\),这代表总体变异性。矩阵 \({\bf V}\) 的第一列是第一主成分,它代表最大方差的方向 \(\frac{1}{m-1} \cdot d_{11}\)。在这里,第一主成分占问题变异性的 \(\frac{d_{11}}{d_{11} + d_{22} + d_{33}} \cdot\) 100%。

SVD 和数据转换
我们知道 \({\bf A}^T {\bf A}\) 的特征向量是 \({\bf A}\) 的右奇异向量,或者是 \({\bf A}\) 的奇异值分解(SVD)中的 \({\bf V}\) 的列(或者是 \({\bf V}\) 转置的行)。因此,我们不需要计算协方差矩阵和求解特征值问题,而是直接得到 SVD 的简化形式!
从
我们可以通过 \({\bf A}\) 的最大奇异值的平方来获得最大方差,即 \({\sigma ² _{max}}\),这是 \({\bf \Sigma}\) 的最大平方项,以及第一主成分(最大方差的方向)作为 \({\bf V}\) 的对应列。
最后,我们可以根据主成分的方向转换我们的数据集:
\({\bf A V}\) 是数据在主成分上的投影。\({\bf A V_k}\) 是在第一个 \(k\) 个主成分上的投影,其中 \({\bf V_k}\) 代表 \({\bf V}\) 的前 \(k\) 列。
PCA 算法总结
假设我们给定一个维度为 \(m \times n\) 的大数据集 \(\bf A\),我们想要将数据集减少到一个较小的数据集 \({\bf A}^*\)(维度为 \(m \times k\)),而不丢失重要信息。我们可以通过以下步骤执行 PCA 算法来实现这一点:
-
将数据集 \(\bf A\) 平移,使其具有零均值:\({\bf A} = {\bf A} - {\bf A}.mean()\).
-
对原始数据集计算SVD:\({\bf A}= {\bf U \Sigma V}^T\).
-
注意到数据集的方差由 \(\bf A\) 的奇异值决定,即 \(\sigma_1, ... , \sigma_n\)。
-
注意到 \(\bf V\) 的列代表数据集的主方向。
-
我们的新数据集是 \({\bf A}^* := {\bf AV} ={\bf U\Sigma}\)。
-
有时我们想要减少数据集的维度,并且只使用最重要的 \(k\) 个主方向,即 \({\bf V}\) 的前 \(k\) 列。因此,我们可以将上述方程 \({\bf A}^* = {\bf AV}\) 改为 \({\bf A}^* = {\bf AV_k}\),其中 \({\bf A}^*\) 具有所需的维度 \(m \times k\)。
注意到数据集的方差对应于奇异值:\(({\bf A}^*)^T {\bf A}^*= {\bf V}^T{\bf A}^T{\bf AV}={\bf \Sigma}^T{\bf \Sigma}\),如步骤 3 所示。
主成分的替代定义
还有一些其他密切相关的量也被称为主成分。我们将主成分称为方差的方向,即 \(\bf V\) 的列。在某些其他情况下,主成分指的是方差本身,即 \(\sigma_1², ... , \sigma_n²\)。在这种情况下,方差的方向可能被称为主方向。主成分的含义应通过上下文变得清晰。
更新日志
-
2024 年 4 月 18 日:Dev Singh (dsingh14) — 修复解释中的错误
-
2024 年 4 月 3 日:Bhargav Chandaka (bhargav9) — 对内容进行重大重组,以与幻灯片/视频中的内容相匹配
-
2022 年 4 月 18 日:Yuxuan Chen (yuxuan19) — 添加 PCA 定义、数据中心化、协方差矩阵、对角化、svd、示例、总结、替代定义
查看剩余条目
+ 2020 年 11 月 30 日:Jerry Yang (jiayiy7) — 修复 pca 代码
+ 2020 年 8 月 9 日:Yikai Teng (yikait2) — 概述
作者
- CS 357 课程工作人员
演示文稿
这里包含了课程中每个主题的所有幻灯片。
-
02-Python.pdf
-
03-Errors.pdf
-
04a-Binary-Numbers.pdf
-
05-Rounding.pdf
-
06-Taylor.pdf
-
07-MonteCarlo.pdf
-
08-Vectors-and-Matrices.pdf
-
09-Linear-Systems.pdf
-
10-Conditioning.pdf
-
11-Sparse-Matrices.pdf
-
12-Eigenvalues.pdf
-
13-Markov-Chains.pdf
-
14-NonLinear-Equations.pdf
-
15-Optimization.pdf
-
16-SVD.pdf
-
17-LinearLeastSquares.pdf
-
18-PCA.pdf
-
19-Finite-Difference.pdf
-
94-Floating-Point.pdf

浙公网安备 33010602011771号