1. python的scipy.optimize.minimize 介绍

minimize提供的方法能够解决无/有约束的线性或非线性的多个决策变量目标函数的最优化问题,但是由于该模块是依据函数导数与梯度进行求解,不能够求解整数规划、01规划等问题。完整参数如下:

minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)

各个参数的含义如下:

参数 含义 使用说明

fun    

待最小化求解的目标函数(用户自定义) 假设用户有一个自定义方程 fun(x, y, params), 但是使用时不直接传入 fun(x, y, params),而是将其先包装一下,使得fun变成一个仅依赖于params的函数,这样才能通过搜寻合适的params来最小化fun。例如,可以传递这样一个匿名函数(lambda表达式)lambda params: fun(x, y, params) 作为可调用对象
x0     初始化(即目标函数中的参数的初始化值) 一个Array,形状是(n,) n是待搜存参数个数
args    
 
目标函数带参数时需要指定

元组,args 参数用于传递额外的参数给目标函数。它包含除了优化变量外的所有其他参数,这些参数会被直接传递给目标函数及其导数(包括fun、jac 和hess函数)的额外参数。

method     优化器类型
  • ‘Nelder-Mead’ - 尼德勒-米德法(单纯形法的一种)

  • ‘Powell’ - 鲍威尔法

  • ‘CG’ - 共轭梯度法

  • ‘BFGS’ - BFGS拟牛顿法

  • ‘Newton-CG’ - 牛顿-共轭梯度法

  • ‘L-BFGS-B’ - 有限内存BFGS算法(带边界约束)

  • ‘TNC’ - 截断牛顿法(Truncated Newton)

  • ‘COBYLA’ - 线性逼近约束优化方法(Constrained Optimization BY Linear Approximations)

  • ‘COBYQA’ - 此处可能存在误解,通常应为‘COBYLA’,而‘COBYQA’不是标准的优化算法名称。如果是指类似的方法,可能是对原始问题进行二次逼近而非线性逼近。

  • ‘SLSQP’ - 序列最小二乘规划(Sequential Least Squares Programming)

  • ‘trust-constr’ - 信赖域约束算法

  • ‘dogleg’ - 狗腿法(信赖域算法的一种)

  • ‘trust-ncg’ - 信赖域牛顿共轭梯度法

  • ‘trust-exact’ - 精确信赖域法

  • ‘trust-krylov’ - 使用Krylov子空间方法的信赖域优化

如果没有指定,则根据问题是否有约束或边界条件,默认选择 BFGS、L-BFGS-B 或 SLSQP 中的一种。

jac     雅可比矩阵或梯度函数

jac{callable, ‘2-point’, ‘3-point’, ‘cs’, bool}

计算梯度向量的方法,仅适用于CG、BFGS、Newton-CG、L-BFGS-B、TNC、SLSQP、dogleg、trust-ncg、trust-krylov、trust-exact和trust-constr。

  • 如果它是一个自定义函数,它应该是一个返回梯度向量的函数jac(x, *args)。

  • 如果选择‘2-point’, ‘3-point’, ‘cs’,,即数值估计梯度的有限差分方法之一。

  • 如果选择None 或 False,则使用带有绝对步长的2-point有限差分估计来计算梯度。

  • 如果选择True, 则假定 fun 返回一个包含目标函数和梯度的元组 (f, g)。

hess     hessian海塞矩阵

hess{callable, ‘2-point’, ‘3-point’, ‘cs’, HessianUpdateStrategy}

 仅适用于Newton-CG, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr

hessp     海塞向量积

目标函数的Hessian矩阵与任意向量 p 的乘积。仅适用于Newton-CG、trust-ncg、trust-krylov和trust-constr。

只需要提供 hessp 或 hess 其中之一即可。如果提供了 hess,则会忽略 hessp。hessp 必须能够计算Hessian矩阵与任意向量的乘积。

bounds     寻优范围

sequence or bounds,例如

变量的边界适用于Nelder-Mead、L-BFGS-B、TNC、SLSQP、Powell、trust-constr、COBYLA和COBYQA方法。有两种方式可以指定边界:

(1)使用Bounds类的实例:Bounds(lb=-infub=infkeep_feasible=False)

(2)为params中的每个元素指定(min, max)对的序列。使用None表示没有边界。

constraints   限制约束

仅适用于COBYLA、COBYQA、SLSQP和trust-constr方法。

(1)对于'trust-constr'和'COBYQA',约束被定义为一个对象或多个对象的列表。
(2)对于COBYLA和SLSQP,约束被定义为字典的列表。每个字典包含以下字段:

  • type:字符串,表示约束类型,'eq'表示等式约束,'ineq'表示不等式约束。

  • fun:可调用对象,定义约束的函数。

  • jac:可调用对象,可选,fun函数的雅可比矩阵(仅适用于SLSQP)。

  • args:序列,可选,传递给函数和雅可比矩阵的额外参数。

tol    
 
浮点数,误差容差值 算法终止时的容差值。
callback     回调函数

除了TNC、SLSQP和COBYLA之外,所有方法都支持调用回调函数:

callback(intermediate_result: OptimizeResult)
这里intermediate_result是一个关键字参数,包含一个具有params和fun属性的OptimizeResult,分别代表当前参数向量和目标函数的值。需要注意的是,为了使回调函数接收到OptimizeResult,参数名称必须是intermediate_result。

options     字典,不同方法有不同选项 通过一个字典来指定求解器的选项,包括最大迭代次数(maxiter)和是否显示收敛消息(disp)。需要注意的是,TNC方法使用maxfun而不是maxiter来限制函数评估的最大数量。这些选项允许用户更细致地控制优化过程的行为。

更多详细信息可以用show_options:

from scipy.optimize import show_options
show_options(solver="minimize")

# Specifying a method is possible:
show_options(solver="minimize", method="Nelder-Mead")

# We can also get the documentations as a string:
show_options(solver="minimize", method="Nelder-Mead", disp=False)

2. 示例1:用极大似然函数求解回归方程的系数

2.1 写出待求解函数的极大似然函数的数学表达式

 假设我们有一个线性模型y=\beta_0+ \beta_1*x_1+\beta_2*x_2^2+\beta_3*log(x_3)+\epsilon,其中,\epsilon \sim N(0, \sigma^2)。我们的目标是找到一组参数\beta = [\beta_0, \beta_1,\beta_2,\beta_3],使得数据集下的对数似然函数最大。

对于每个观测值i, 残差为e_i = y_i -(\beta_0 + \beta_1x_{1i}+\beta_2x_{2i}^2+\beta_3log(x_{3i})),那么所有观测值的联合概率密度由下式给出:

L(\beta) = \prod_{i=1}^{n} \frac{1}{\sqrt{2\pi}\sigma} \exp\left(-\frac{(y_i - f(x_i; \beta))^2}{2\sigma^2}\right)

最大化似然函数等价于最小化负对数似然函数:

-\log(L(\beta)) = \frac{n}{2} \log(2\pi\sigma^2) + \frac{1}{2\sigma^2} \sum_{i=1}^{n} (y_i - f(x_i; \beta))^2

由于第一项与\beta 无关,我们可以忽略它,从而简化问题为最小化第二项:

\text{MSE}(\beta) = \frac{1}{2} \sum_{i=1}^{n} (y_i - f(x_i; \beta))^2

2.2 用scipy.optimize.minimize来求解极大似然函数

示例代码如下所示:

import pandas as pd
import numpy as np
from scipy.optimize import minimize

# Step 1: Define the function and the negative log-likelihood
def model_function(beta, x):
    return beta[0] + beta[1] * x[:, 0] + beta[2] * x[:, 1]**2 + beta[3] * np.log(x[:, 2])
def neg_log_likelihood(beta, x, y):
    residuals = y - model_function(beta, x)
    mse = np.mean(residuals**2)
    n = len(y)
    return mse

# Step 2: Generate synthetic data
# step 2.1 generate x
np.random.seed(42)
n_samples = 10000
x1 = np.random.rand(n_samples)
x2 = np.random.rand(n_samples)
x3 = np.random.uniform(1, 10, n_samples)  # Ensure x3 > 0 for log calculation
X = np.column_stack((x1, x2, x3))
# step 2.1 generate beta & y
true_beta = [1, 2, 3, 4]  # True parameters for generating data
noise = np.random.normal(0, 1, n_samples)
y = model_function(true_beta, X) + noise

# Step 3: Use scipy.optimize.minimize to find the optimal beta
initial_guess = [0, 0, 0, 0]
result = minimize(neg_log_likelihood, initial_guess, args=(X, y), method='BFGS',options={'disp': True})
print(result)
estimated_beta = result.x
print("Estimated Beta:", estimated_beta)
# 另外一种方法,用于对比lambda和args的写法,二者都可以实现目的
result = minimize(lambda beta: neg_log_likelihood(beta, X, y), initial_guess, method='BFGS')
estimated_beta = result.x
print("Estimated Beta:", estimated_beta)
# Estimated Beta: [1.0117673  1.98887947 3.01406188 3.98902748]
# 再换一种优化器,Nelder-Mead单纯形法
result = minimize(lambda beta: neg_log_likelihood(beta, X, y), initial_guess, method='Nelder-Mead')
print("Estimated Beta:", result.x)
# Estimated Beta: [1.01095591 1.98947494 3.01293004 3.98956425]

3. 最优化算法的介绍

不同的优化器适用于不同类型的优化问题,主要取决于目标函数的特性(如是否平滑、是否存在约束等)。以下是对每种优化器适用场景的简要说明:

  • Nelder-Mead:适用于无约束优化问题。它不使用梯度信息,因此适合于不可微或难以计算导数的目标函数。

  • Powell:适用于无约束优化问题,尤其是当梯度难以计算时。它是一种共轭方向方法。

  • CG (Conjugate Gradient):适用于大规模无约束优化问题,特别是当目标函数是二次可微的时候。它比简单的梯度下降更高效。

  • BFGS (Broyden–Fletcher–Goldfarb–Shanno):一种拟牛顿法,适用于无约束优化问题。它利用近似Hessian矩阵来加速收敛,适用于平滑函数。

  • Newton-CG:结合了牛顿法和共轭梯度法的优点,适用于无约束优化问题,尤其是目标函数及其梯度和Hessian矩阵都容易计算的情况。

  • L-BFGS-B:有限内存BFGS算法的变体,支持边界约束条件下的优化问题。

  • TNC (Truncated Newton):适用于带有变量边界的大型无约束优化问题。它是为数值稳定性设计的一种截断牛顿算法。

  • COBYLA (Constrained Optimization BY Linear Approximations):适用于带约束的优化问题,特别是当约束条件是非线性的,且不需要精确的梯度信息时。

  • COBYQA:似乎是指“Constrained Optimization BY Quadratic Approximation”,这是一种基于二次逼近的方法,用于处理有约束的优化问题。但请注意,这并非标准命名,可能是对某些特定实现的误称。

  • SLSQP (Sequential Least Squares Programming):适用于带有等式和/或不等式约束的优化问题,能够有效地处理非线性约束。

  • trust-constr:信赖域算法,适用于具有复杂约束条件的问题,包括等式和不等式约束。

  • dogleg:信赖域方法的一种,适用于需要快速局部收敛的情况,通常用于解决非线性最小二乘问题。

  • trust-ncg (Newton Conjugate Gradient):信赖域牛顿共轭梯度法,适用于需要高精度解的大规模无约束优化问题。

  • trust-exact:精确信赖域方法,适用于需要高精度解的小到中等规模的优化问题。

  • trust-krylov:使用Krylov子空间方法的信赖域优化,适用于大规模问题,尤其是当求解Hessian矩阵与向量的乘积比较经济时。

选择合适的优化器取决于具体问题的特点,如目标函数的形式、是否有约束条件以及这些约束的性质等。

4. 示例2:待约束条件的最优化求解

假设我们要最小化以下函数:

f(x) = (x_1 - 1)^2 + (x_2 - 2.5)^2

同时,我们有以下约束条件:

x_1 + x_2 \geq 1 \\ x_1^2 + x_2^2 \leq 4 \\

此外,我们还有边界条件:

0 \leq x_1 \leq 3 \\ 0 \leq x_2 \leq 3 \\

使用 scipy.optimize.minimize 求解

代码如下所示:

import numpy as np
from scipy.optimize import minimize

# Step 1: Define the objective function
def objective_function(x):
    return (x[0] - 1)**2 + (x[1] - 2.5)**2

# Step 2: Define the constraints
constraints = [
    {'type': 'ineq', 'fun': lambda x: x[0] + x[1] - 1},  # x1 + x2 >= 1
    {'type': 'ineq', 'fun': lambda x: 4 - (x[0]**2 + x[1]**2)}  # x1^2 + x2^2 <= 4
]

# Step 3: Define the bounds for each variable
bounds = [(0, 3), (0, 3)]  # 0 <= x1 <= 3, 0 <= x2 <= 3

# Step 4: Initial guess
initial_guess = [0, 0]

# Step 5: Use scipy.optimize.minimize to find the optimal solution
result = minimize(objective_function, initial_guess, method='SLSQP', bounds=bounds, constraints=constraints)

# Print the results
print("Optimal Solution:", result.x)
print("Objective Function Value at Optimal Solution:", result.fun)
print("Success:", result.success)
print("Message:", result.message)
# Optimal Solution: [0.74278177 1.85695322]
# Objective Function Value at Optimal Solution: 0.4796703779910314
# Success: True
# Message: Optimization terminated successfully

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐