【机器学习】机器学习中用到的高等数学知识-4.数值分析 (Numerical Analysis)
- 优化方法:用于寻找函数的极值(如牛顿法、随机梯度下降)。
- 插值和拟合:用于处理数据点之间的关系,生成模型。
数值分析(Numerical Analysis)是数学的一个分支,专注于开发用于数值近似的方法,以解决科学和工程问题中的复杂数学运算。它为无法用解析方法求解的问题提供了近似解,通过数值方法来保证计算结果的精确度和效率。数值分析的应用领域非常广泛,包括求解线性和非线性方程组、积分、微分方程、最优化问题、特征值计算等。
数值分析的主要内容
-
线性代数的数值方法:如矩阵分解、迭代法、特征值问题,用于处理线性方程组和向量空间的问题。
-
插值与逼近:研究多项式插值、样条插值及逼近方法,常用于数据拟合和曲线拟合。
-
数值微分和积分:包括数值积分(如梯形法、辛普森法)和数值微分,用于近似求解积分和导数。
-
常微分方程与偏微分方程的数值解:开发数值方法来求解微分方程,广泛用于物理模拟、流体动力学等领域。
-
优化算法:包括梯度下降法、牛顿法等,用于求解极值问题。
数值分析的特点
- 误差分析:在数值分析中,误差的来源通常包括截断误差和舍入误差,研究误差传播和收敛性是数值分析的重要部分。
- 稳定性和收敛性:确保数值方法在迭代过程中逐步逼近准确解,并对计算中的不稳定性进行控制。
应用
数值分析在科学计算、工程设计、物理模拟、金融计算等领域广泛应用,是现代计算科学和工程的重要支柱。
优化方法
优化方法在数值分析中用于寻找函数的极值点,广泛应用于机器学习、工程设计和经济学等领域。常见的优化方法包括:
-
牛顿法:
一种基于二阶导数的迭代方法,用于快速逼近函数的极值,适用于凸函数和可导函数。牛顿法利用泰勒展开来逼近目标函数的根,从而找到极值点。
假设我们要最小化一个函数 f(x),其迭代公式为:
这里:
f'(x) 是函数 f(x) 的一阶导数(梯度),表示变化方向。
f''(x) 是函数 f(x) 的二阶导数(Hessian 矩阵在高维中),表示曲率。
示例:假设 ,我们可以手动计算其导数并使用牛顿法来求解最小值点。
f'(x) = 2x - 4
f''(x) = 2
根据牛顿法的迭代公式,有:
即每一步迭代都会收敛到最小值点 x = 2。
Python代码实现:
def newton_method(f_prime, f_double_prime, x0, tol=1e-5, max_iter=100):
x = x0
for _ in range(max_iter):
x_new = x - f_prime(x) / f_double_prime(x)
if abs(x_new - x) < tol:
break
x = x_new
return x
# 定义 f'(x) 和 f''(x)
f_prime = lambda x: 2*x - 4
f_double_prime = lambda x: 2
# 初始猜测值
x0 = 0
min_x = newton_method(f_prime, f_double_prime, x0)
print(f"牛顿法找到的最小值点 x = {min_x}")
牛顿法找到的最小值点 x = 2.0
-
随机梯度下降 (SGD):
用于求解大规模优化问题的迭代算法。随机梯度下降在每步迭代中使用一个或多个样本计算梯度,从而有效地降低计算复杂度。它在机器学习中的模型训练和参数优化中非常重要。
在 SGD 中,给定学习率 α 和梯度 ∇f(x),更新公式为:
示例:假设我们要最小化 ,其梯度为 。
Python代码实现:
import numpy as np
def stochastic_gradient_descent(f_prime, x0, alpha=0.1, tol=1e-5, max_iter=100):
x = x0
for _ in range(max_iter):
grad = f_prime(x)
x_new = x - alpha * grad
if abs(x_new - x) < tol:
break
x = x_new
return x
# 定义 f'(x)
f_prime = lambda x: 2 * (x - 3)
# 初始猜测值
x0 = 0
min_x = stochastic_gradient_descent(f_prime, x0)
print(f"SGD 找到的最小值点 x = {min_x}")
SGD 找到的最小值点 x = 2.9999571825692186
插值和拟合
插值和拟合用于构建数据点之间的关系模型,帮助我们在离散数据点之间找到近似的连续函数。常见的方法有:
-
多项式插值:
通过构建一个多项式函数来精确通过一组给定的数据点。拉格朗日插值和牛顿插值是常用的多项式插值方法。然而,高次多项式插值可能会导致龙格现象(振荡现象),因此通常只适用于低维数据或少量数据点。
对于 n+1 个数据点 ,可以找到一个 n 次多项式 P(x) 使得 。
拉格朗日插值法 是一种经典的插值方法,其多项式形式为:
Python代码实现:
from scipy.interpolate import lagrange
# 数据点
x_data = np.array([0, 1, 2, 3])
y_data = np.array([1, 2, 0, 3])
# 使用拉格朗日插值
poly = lagrange(x_data, y_data)
print(f"插值多项式: {poly}")
-
样条插值:
用低次多项式在相邻数据点之间插值。常用的三次样条插值具有较好的平滑性,避免了多项式插值中的振荡问题,广泛用于曲线拟合和平滑。
假设有一组数据点 ,我们希望在这些点之间构造一组三次多项式,使得:
- 每个多项式在其区间内精确通过数据点。
- 多项式的值和导数在相邻区间的端点处连续。
公式推导
对于每个区间 ,设三次样条函数为:
为了确定这些系数 ,需要满足以下条件:
-
插值条件:在每个节点 处满足
-
光滑条件:在每个内部节点上函数值、导数及二阶导数连续,即:
-
边界条件:可选用自然边界条件(即二阶导数在端点为零)或其他条件以确定端点。
这些条件形成一个线性方程组,解出系数 后,就可以构造出样条函数。
Python代码实现:
Python 中的 scipy.interpolate
库提供了样条插值的实现,使用 CubicSpline
类可以轻松进行三次样条插值。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
# 数据点
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([0, 1, 0, 1, 0, 1])
# 三次样条插值
cs = CubicSpline(x, y, bc_type='natural') # 使用自然边界条件
# 在区间内生成更多点
x_new = np.linspace(0, 5, 100)
y_new = cs(x_new)
# 绘图
plt.figure(figsize=(8, 6))
plt.plot(x, y, 'o', label='Data Points')
plt.plot(x_new, y_new, label='Cubic Spline Interpolation')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.title("Cubic Spline Interpolation Example")
plt.grid(True)
plt.show()
解释和图解
在上面的代码中,我们首先定义了已知的离散数据点,然后使用 CubicSpline
进行三次样条插值。在图中,圆点表示原始数据点,平滑的曲线为插值后的三次样条函数。
样条插值的应用
样条插值在许多领域有广泛应用,如:
- 图形学:用于绘制平滑曲线和路径。
- 信号处理:对离散信号进行平滑处理。
- 数值分析:构造平滑函数以便对数据进行分析和建模。
样条插值提供了一种灵活的平滑插值方法,在处理噪声数据或稀疏数据时表现出色。
最小二乘拟合:
用来寻找数据点的最佳拟合模型,通过最小化误差的平方和来得到参数估计。它适用于数据噪声较大的情况,如线性回归和多项式回归,用于数据分析和预测建模。
其目标函数为:
Python代码实现:
from numpy.polynomial.polynomial import Polynomial
import numpy as np
x_data = np.array([0, 1, 2, 3])
y_data = np.array([1, 2, 0, 3])
# 使用 numpy 的最小二乘拟合
coeffs = np.polyfit(x_data, y_data, deg=2) # 2 次多项式拟合
poly_fit = Polynomial(coeffs[::-1]) # 调整系数顺序
# 打印拟合多项式
print(f"最小二乘拟合多项式: {poly_fit}")
最小二乘拟合多项式: 1.4 - 1.1 x + 0.5 x**2
使用 Matplotlib 绘制出插值和拟合的结果
这个绘图代码将生成两个曲线,分别是通过拉格朗日插值得到的插值多项式曲线和通过最小二乘拟合得到的拟合多项式曲线,从而更直观地展示插值与拟合的差异和效果。
import numpy as np
from numpy.polynomial.polynomial import Polynomial
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange
x_data = np.array([0, 1, 2, 3])
y_data = np.array([1, 2, 0, 3])
# 使用拉格朗日插值
poly = lagrange(x_data, y_data)
# 插值
x_interp = np.linspace(min(x_data), max(x_data), 100)
y_interp = poly(x_interp)
# 使用 numpy 的最小二乘拟合
coeffs = np.polyfit(x_data, y_data, deg=2) # 2 次多项式拟合
poly_fit = Polynomial(coeffs[::-1]) # 调整系数顺序
# 最小二乘拟合
y_fit = poly_fit(x_interp)
# 绘图
plt.figure(figsize=(10, 5))
plt.plot(x_data, y_data, 'o', label='Data Points')
plt.plot(x_interp, y_interp, label='Lagrange Interpolation', linestyle='--')
plt.plot(x_interp, y_fit, label='Least Squares Fit', linestyle='-')
plt.legend()
plt.title("Interpolation and Least Squares Fit")
plt.xlabel("x")
plt.ylabel("y")
plt.grid(True)
plt.show()
简单的插值与优化
以下示例展示了多项式插值和梯度下降优化方法的简单实现。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy.optimize import minimize
# 样本数据点
x_data = np.array([0, 1, 2, 3, 4, 5])
y_data = np.array([1, 2.5, 0.5, 2, 1.5, 3])
# 插值
linear_interp = interp1d(x_data, y_data, kind='linear')
x_new = np.linspace(0, 5, 100)
y_new = linear_interp(x_new)
# 优化示例(最小化一个简单的函数 f(x) = (x-2)^2)
def objective(x):
return (x - 2) ** 2
result = minimize(objective, x0=0) # 初始猜测 x0=0
# 绘图
plt.figure(figsize=(12, 5))
# 插值图
plt.subplot(1, 2, 1)
plt.plot(x_data, y_data, 'o', label='Data Points')
plt.plot(x_new, y_new, '-', label='Linear Interpolation')
plt.title("Linear Interpolation")
plt.legend()
# 优化结果展示
plt.subplot(1, 2, 2)
x = np.linspace(-1, 5, 100)
y = objective(x)
plt.plot(x, y, label=r'$f(x) = (x-2)^2$')
plt.plot(result.x, result.fun, 'ro', label='Minimized Point')
plt.title("Optimization (Minimizing f(x))")
plt.legend()
plt.show()
这段代码生成了插值与优化的图示,展示了数值分析中的两个常用方法。