跳至主要内容

Python 优化:技术、包与最佳实践

本文介绍数值优化并重点阐述不同技术,讨论 SciPy、CVXPY 和 Pyomo 等 Python 包,并提供可运行示例代码的 DataLab 笔记本。
· 11分钟 阅读

使用 AI 探索

优化是机器学习中的核心技术之一。我最初学习的就是它,但很快发现它的应用远远超出机器学习的范畴。

数值优化在各个领域解决复杂问题中发挥着关键作用。没有它,数据科学家、经济学家和工程师都会陷入构建低效且昂贵的工具、并做出非最优决策的困境。

这就是为什么本文要介绍Python 中的优化,涵盖最常用的包、技术和最佳实践。

系好安全带,准备出发,并配合这个 DataLab 工作簿一起学习。

什么是数值优化?

现实世界中的许多问题很难直接求得最优解。解决这些问题需要迭代式的方法,而这正是数值优化大显身手之处。

数值优化是指使用迭代计算方法寻找函数的最小值或最大值,而不是通过代数推导得到解析解。

不同于可能给出闭式精确解的解析方法,数值优化依赖算法在多次迭代中逐步改进估计值,从而逼近最优解。

当处理如下类型的函数时,这种方法尤为有用:

  • 复杂
  • 非线性
  • 高维

在这类场景中,解析法要么不可行,要么成本过高,因此采用迭代方法更为合适。

常见优化问题

在数值优化中,通常根据目标函数的性质以及是否存在约束对问题进行分类。

因此,最常见的问题可以分为以下几类:

无约束优化

这是最简单的优化形式。其目标是在不对变量施加限制的情况下,寻找目标函数的最小值或最大值。

目标是仅基于函数的数学结构,确定其达到最优值(最小或最大)的位置。

诸如梯度下降或牛顿法等技术常用于求解无约束问题(后文会详细介绍)。方法的重点在于通过评估函数的导数来迭代改进解。

例如,最小化一个依赖于一个或多个变量 x 的代价函数 f(x),且对 x 的取值没有任何限制,就是典型的无约束问题。

有约束优化

另一方面,有约束优化问题要求在变量受到一个或多个约束的条件下,找到目标函数的最优值。这些约束可以是等式或不等式。

有约束优化的挑战在于既要优化函数,又要确保解满足给定的约束。

例如,在工程设计中,一个典型的有约束优化问题可能是最小化材料成本(目标函数),同时满足强度或重量等物理限制(约束)。

常见的方法包括拉格朗日乘子、罚函数和屏障法等,用于将这些约束纳入优化过程。

线性与非线性优化

在线性优化中,目标函数和约束都是——没错——线性的。这意味着变量之间的关系由线性方程或不等式表示。

线性优化问题的解空间通常更简单、结构更清晰,常可用单纯形法或内点法等高效求解。

线性优化的经典例子是线性规划问题,其目标可能是在资源约束(线性不等式)下最大化利润(线性函数)。

相比之下,非线性优化包含非线性的目标函数或约束,使问题显著更复杂。

在现实应用中,我们经常会遇到变量关系并不简单的非线性优化问题。这类问题可能存在多个局部最优,比线性问题更具挑战。

常用技术包括基于梯度的方法、牛顿法以及进化算法等来处理非线性优化。

非线性优化的一个示例是最小化具有复杂物理依赖的能量函数,例如为获得更高气动效率而优化飞机机翼形状,其中设计变量与性能指标之间存在非线性关系。

Python 中的优化技术

Python 提供了多种强大的方法来解决优化问题,既包括简单的基于梯度的方法,也涵盖更复杂的算法。无论是在机器学习、工程还是运筹学中,这些技术都能帮助您高效寻找函数的极小值或极大值。

本节将介绍 Python 中常见的优化技术,包括梯度下降、牛顿法、共轭梯度法、拟牛顿法、单纯形法以及信赖域方法。

提示:查看这个DataLab,了解本节用于生成可视化的全部代码。

让我们开始吧!

梯度下降

梯度下降是数值优化中最基础的技术之一。它是一种迭代方法,通过沿函数梯度(或斜率)的负方向前进来寻找函数的最小值。

核心思想是从一个初始猜测开始,沿最陡下降方向迭代更新,直至收敛。它是训练机器学习模型时最常用的优化技术之一,目标是最小化损失函数。

梯度下降曲线图像   

牛顿法

牛顿法是一种利用目标函数的一阶导数和二阶导数(海森矩阵)来寻找极小值的优化技术。不同于只依赖一阶导数的梯度下降,牛顿法利用曲率信息,能更快收敛,尤其适用于凸函数。

尽管牛顿法收敛迅速,但需要计算海森矩阵,这在大规模问题中可能计算开销高且不切实际。不过,对于小规模、平滑且凸的问题,它非常有效。

牛顿法曲线图像

共轭梯度法

共轭梯度法是一种适用于大规模问题的高效优化技术,特别是在存储海森矩阵不切实际的情况下。它通过迭代构造共轭方向并沿这些方向优化,而不需要完整的海森矩阵,适合例如最小化大型二次函数的问题。

该方法在有限元分析或大规模机器学习应用中非常有用,因为这些场景的矩阵计算负担较重。

共轭梯度法图像

拟牛顿法(BFGS)

拟牛顿法(如 Broyden–Fletcher–Goldfarb–Shanno,BFGS 算法)通过近似海森矩阵而非直接计算来加速收敛。与梯度下降相比,这些方法利用二阶信息而无需承担计算完整海森矩阵的开销,因此通常收敛更快。

BFGS 方法图像

单纯形法

单纯形法是求解线性规划(LP)问题的广泛使用算法,其中目标函数和约束均为线性。它系统地检查可行域(一个多面体)的顶点,并朝着使目标函数达到最大或最小值的最优顶点移动。

线性函数上的单纯形法图像

信赖域方法

信赖域方法是在当前解的“信赖域”内构建目标函数的局部模型的优化算法。

与按预定方向前进(如梯度下降)不同,该算法在信赖域内定义一个更简单的子问题,并通过反复求解该子问题来改进解。这些方法在处理复杂的非线性问题时尤为有效,相比传统的基于梯度的方法具有更好的稳定性。

最小化 Rosenbrock 函数时的信赖域与半径图像

最小化 Rosenbrock 函数时的信赖域与半径 | 来源:Shivangi Khare 的 Trust Region Methods

常见的 Python 优化包

有许多用于数值优化的库和包。各有侧重与适用场景,但无论您面对何种优化问题,通常都能在 Python 中找到稳健的工具来应对。

以下是四个最常见的优化包:

SciPy 优化(scipy.optimize)

scipy.optimize 模块是 SciPy 生态中的多功能库,提供了广泛的算法来解决无约束和有约束优化问题。它包含用于寻找标量与多变量函数极小值的函数、求解求根问题以及拟合数据曲线的工具。

该模块中的函数包括:

  • minimize():用于最小化一个或多个变量的标量函数。
from scipy.optimize import minimize

def objective_function(x):
    return x[0]**2 + x[1]**2
result = minimize(objective_function, [1, 1], method='BFGS')
print(result.x)  # Optimal solution

# >>> [-1.07505143e-08 -1.07505143e-08]
  • root():求解向量函数的根——在解决非线性方程组时非常有用。
from scipy.optimize import root

def equations(vars):
    x, y = vars
    return [x + 2*y - 3, x - y - 1]
result = root(equations, [0, 0])
print(result.x)

# >>> [1.66666667 0.66666667]
  • curve_fit():将曲线拟合到一组数据点,适用于数据拟合与参数估计。
from scipy.optimize import curve_fit
import numpy as np

def model(x, a, b):
    return a * np.exp(b * x)
x_data = np.array([1, 2, 3])
y_data = np.array([2.7, 7.4, 20.1])
params, covariance = curve_fit(model, x_data, y_data)
print(params)  # Fitted parameters

# >>> [0.9981286  1.00089935]

CVXPY

CVXPY 是专为凸优化问题设计的 Python 库。它使用高级的声明式语法来定义和求解这类问题。通过以直观可读的方式指定目标函数和约束,CVXPY 简化了复杂优化问题的建模过程。

CVXPY 具备以下特性:

  • 声明式语法: 通过 Python 的数学表达式直观建模优化问题。
  • 前沿求解器: 可与 ECOS、SCS、OSQP 等高级求解器对接,高效处理凸问题。
import cvxpy as cp

# Define variables
x = cp.Variable()
y = cp.Variable()

# Define constraints
constraints = [x + y == 1, x - y >= 2]

# Define the objective function
objective = cp.Minimize(x**2 + y**2)

# Formulate the problem
prob = cp.Problem(objective, constraints)

# Solve the problem
result = prob.solve()
print(f"Optimal value: {result}")
print(f"x: {x.value}, y: {y.value}")

# >>> Optimal value: 2.5
# x: 1.5, y: -0.5000000000000001

Pyomo

Pyomo 是一个灵活而全面的优化建模包,支持线性、非线性和混合整数规划。它面向复杂优化问题设计,并可与 GLPK、CBC 和 CPLEX 等求解器无缝集成。

Pyomo 的特性包括:

  • 建模灵活性: 可高度灵活地定义优化问题,包括复杂的约束与目标。
  • 求解器集成: 支持广泛的求解器,便于为特定问题选择最合适的工具。

Gurobi 与 CPLEX(通过 Pyomo 或直接 API)

Gurobi 和 CPLEX 是面向大规模优化问题的高性能求解器。它们广泛用于供应链优化、投资组合管理与物流等行业场景。

它们提供先进算法,能够高效处理复杂且大规模的问题。

  • Gurobi:可通过 Pyomo 或其直接 API 使用,以在线性、整数与二次规划问题中的速度与可靠性著称。
  • CPLEX:同样提供强大的优化能力,被广泛用于解决各行业中的复杂运营与战略问题。可通过 Pyomo 或其 API 直接访问。

在需要计算效率与稳健性至关重要的工业级问题中,常采用这些求解器。

Python 数值优化的真实应用

正如在引言中提到的,数值优化在多个领域都扮演着关键角色。它为解决复杂问题与做出数据驱动决策提供了基本技术。

例如:

  • 机器学习:模型本质上是通过数值优化进行训练的。这涉及找到使损失函数最小化的最优参数,并量化模型对目标变量的预测效果。
  • 运筹学:优化技术帮助做出最大化或最小化各类运营指标的战略决策。通过在约束条件下优化目标函数,运筹学家可以改进供应链管理、人员排班、生产计划等流程的效率。
  • 金融: 数值优化在金融领域至关重要,例如投资组合优化。它有助于确定最佳资产配置,以最大化回报或最小化风险。
  • 工程设计: 数值优化可用于设计满足特定性能指标且成本最低的系统与结构。这一过程有助于在桥梁、飞机到制造工艺与能源系统等领域实现高效设计。

Python 数值优化的最佳实践

为确保在 Python 中获得最佳优化效果,需要考虑多方面因素。请遵循以下最佳实践:

选择合适的算法

选择正确的优化算法对于获得理想结果至关重要。算法选择取决于问题的性质:

  • 线性 vs. 非线性: 对于线性问题,单纯形法或内点法等线性规划技术更合适。对于非线性问题,可考虑梯度下降、牛顿法或拟牛顿法(如 BFGS)。
  • 有约束 vs. 无约束: 有约束问题需要顺序二次规划(SQP)或原生支持约束的方法(如内点法)。无约束问题则可高效采用梯度下降或牛顿法。

基于问题特性选择合适算法,有助于更快收敛并获得更准确的解。

处理约束

优化问题中的约束会显著影响算法与求解策略。可采用多种方法处理约束:

  • 罚函数法: 通过在目标函数中加入对违反约束的罚项,将有约束问题转化为无约束问题,从而使用无约束优化方法。
  • 屏障法: 使用屏障函数确保不违反约束。屏障法通过在目标函数中加入当接近约束边界时趋于无穷大的屏障项来起作用。
  • 原生支持: 使用原生支持约束的求解器。许多现代优化求解器(如 scipy.optimize 或 CVXPY 提供的)都能直接且高效地处理约束。

选择合适的约束处理方法可确保解可行并满足所有要求。

缩放与预处理

恰当的数据缩放与预处理可以显著提升优化算法的性能:

  • 缩放: 对输入数据进行归一化或标准化,确保各特征对目标函数的贡献相当。这有助于避免数值稳定性问题并提升收敛速度。
  • 预处理: 采用特征工程或降维等技术简化问题。合理的预处理可降低优化问题的复杂度,加快求解过程。

解释结果

解读优化算法的结果需要关注以下方面:

  • 解的质量: 检查是否满足最优性条件与约束;将结果与已知基准对比,或通过交叉验证等方式验证。
  • 收敛判据: 通过收敛信息、迭代次数或目标函数值变化评估算法是否已收敛,确保已经接近真实最优解。
  • 数值精度: 注意数值精度对结果的影响。轻微的数值误差可能累积并影响最终解,尤其在大规模问题或容差较严的场景中。

总结

数值优化是现代问题求解的基石。它为机器学习、工程、金融与运筹学等领域中的复杂挑战提供了强大工具。

Python 丰富的优化库生态——如 SciPy、CVXPY 与 Pyomo——让这些高级技术更为易用,助力研究人员、工程师与数据科学家设计高效系统、优化模型,并做出更明智的数据驱动决策。

掌握合适的技术与最佳实践后,您已经具备处理并解决 Python 中各类棘手优化问题的能力。继续学习请参考以下资源:

FAQs

什么是优化?

优化是使用迭代计算方法而非解析解来寻找函数最小值或最大值的过程。

为什么优化很重要?

优化之所以重要,是因为在机器学习、工程和金融等领域,直接求解往往不切实际或不可能,而优化能帮助解决复杂的现实问题。

哪些 Python 包最适合数值优化?

常用的 Python 数值优化包包括 SciPy(通用优化)、CVXPY(凸优化)、Pyomo(灵活建模),以及 Gurobi 和 CPLEX 等强大求解器,适用于大规模工业应用。

数值优化在机器学习中如何使用?

在机器学习中,数值优化用于最小化损失函数,该函数衡量模型对目标变量的预测效果。

有约束优化与无约束优化有什么区别?

无约束优化是在不对变量施加任何限制的情况下,寻找目标函数的最优值。相反,有约束优化对变量施加限制(如等式或不等式),并要求在优化函数的同时,最优解必须满足这些约束。

Kurtis Pykes

作者

Kurtis Pykes

主题