Skip to content

优化算法

SciPy 的 scipy.optimize 模块提供了丰富的数值优化算法,用于解决各种优化问题。无论是寻找函数的最小值、求解方程组,还是进行参数拟合,这个模块都能提供强大的工具。本章将详细介绍如何使用这些优化算法解决实际问题。

scipy.optimize 模块概述

scipy.optimize 模块包含以下主要功能:

  • 标量函数优化(单变量和多变量)
  • 约束优化和无约束优化
  • 全局优化算法
  • 方程求根
  • 最小二乘拟合
  • 线性规划
  • 非线性规划
python
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import warnings
warnings.filterwarnings('ignore')

# 设置绘图样式
plt.style.use('seaborn-v0_8')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 查看 optimize 模块的主要功能
print("scipy.optimize 主要功能:")
functions = [attr for attr in dir(optimize) if not attr.startswith('_')]
print(f"总共 {len(functions)} 个函数和类")
print("部分函数:", functions[:15])

标量函数优化

1. 单变量函数优化

寻找最小值

python
# 定义测试函数
def f1(x):
    """简单的二次函数"""
    return x**2 + 4*x + 3

def f2(x):
    """复杂的多峰函数"""
    return x**4 - 3*x**3 + 2*x**2 + 2*x - 1

def f3(x):
    """三角函数"""
    return np.sin(x) + 0.1*x**2

# 可视化函数
x = np.linspace(-5, 5, 1000)

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

functions = [(f1, "二次函数"), (f2, "多峰函数"), (f3, "三角函数")]

for i, (func, name) in enumerate(functions):
    y = [func(xi) for xi in x]
    axes[i].plot(x, y, 'b-', linewidth=2)
    axes[i].set_title(name)
    axes[i].set_xlabel('x')
    axes[i].set_ylabel('f(x)')
    axes[i].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 使用不同方法寻找最小值
print("单变量函数优化结果:")

for func, name in functions:
    print(f"\n{name}:")
    
    # 黄金分割法
    result_golden = optimize.minimize_scalar(func, method='golden')
    print(f"  黄金分割法: x={result_golden.x:.6f}, f(x)={result_golden.fun:.6f}")
    
    # Brent 方法
    result_brent = optimize.minimize_scalar(func, method='brent')
    print(f"  Brent 方法: x={result_brent.x:.6f}, f(x)={result_brent.fun:.6f}")
    
    # 有界优化
    result_bounded = optimize.minimize_scalar(func, bounds=(-3, 3), method='bounded')
    print(f"  有界优化: x={result_bounded.x:.6f}, f(x)={result_bounded.fun:.6f}")

寻找最大值

python
# 寻找最大值(通过最小化负函数)
def find_maximum(func, bounds=None):
    """寻找函数的最大值"""
    neg_func = lambda x: -func(x)
    
    if bounds:
        result = optimize.minimize_scalar(neg_func, bounds=bounds, method='bounded')
    else:
        result = optimize.minimize_scalar(neg_func, method='brent')
    
    return result.x, -result.fun

# 测试函数
def test_func(x):
    return -(x - 2)**2 + 5

x_max, f_max = find_maximum(test_func, bounds=(0, 4))
print(f"\n最大值优化:")
print(f"最大值点: x = {x_max:.6f}")
print(f"最大值: f(x) = {f_max:.6f}")

# 可视化
x = np.linspace(0, 4, 1000)
y = [test_func(xi) for xi in x]

plt.figure(figsize=(8, 6))
plt.plot(x, y, 'b-', linewidth=2, label='f(x) = -(x-2)² + 5')
plt.plot(x_max, f_max, 'ro', markersize=10, label=f'最大值 ({x_max:.3f}, {f_max:.3f})')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('寻找函数最大值')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

2. 多变量函数优化

无约束优化

python
# 定义多变量测试函数
def rosenbrock(x):
    """Rosenbrock 函数(香蕉函数)"""
    return 100 * (x[1] - x[0]**2)**2 + (1 - x[0])**2

def himmelblau(x):
    """Himmelblau 函数(多个全局最小值)"""
    return (x[0]**2 + x[1] - 11)**2 + (x[0] + x[1]**2 - 7)**2

def sphere(x):
    """球面函数"""
    return np.sum(x**2)

def rastrigin(x):
    """Rastrigin 函数(多峰函数)"""
    A = 10
    n = len(x)
    return A * n + np.sum(x**2 - A * np.cos(2 * np.pi * x))

# 可视化二维函数
def plot_2d_function(func, bounds, title, levels=20):
    x = np.linspace(bounds[0], bounds[1], 100)
    y = np.linspace(bounds[0], bounds[1], 100)
    X, Y = np.meshgrid(x, y)
    Z = np.zeros_like(X)
    
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Z[i, j] = func([X[i, j], Y[i, j]])
    
    plt.figure(figsize=(10, 8))
    
    # 等高线图
    plt.subplot(2, 2, 1)
    contour = plt.contour(X, Y, Z, levels=levels)
    plt.colorbar(contour)
    plt.title(f'{title} - 等高线图')
    plt.xlabel('x₁')
    plt.ylabel('x₂')
    
    # 填充等高线图
    plt.subplot(2, 2, 2)
    contourf = plt.contourf(X, Y, Z, levels=levels, cmap='viridis')
    plt.colorbar(contourf)
    plt.title(f'{title} - 填充等高线图')
    plt.xlabel('x₁')
    plt.ylabel('x₂')
    
    # 3D 表面图
    ax = plt.subplot(2, 2, 3, projection='3d')
    surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
    ax.set_title(f'{title} - 3D 表面图')
    ax.set_xlabel('x₁')
    ax.set_ylabel('x₂')
    ax.set_zlabel('f(x₁, x₂)')
    
    # 3D 等高线图
    ax = plt.subplot(2, 2, 4, projection='3d')
    ax.contour(X, Y, Z, levels=levels)
    ax.set_title(f'{title} - 3D 等高线图')
    ax.set_xlabel('x₁')
    ax.set_ylabel('x₂')
    ax.set_zlabel('f(x₁, x₂)')
    
    plt.tight_layout()
    plt.show()
    
    return X, Y, Z

# 可视化 Rosenbrock 函数
X, Y, Z = plot_2d_function(rosenbrock, (-2, 2), 'Rosenbrock 函数')

# 使用不同优化方法
test_functions = [
    (rosenbrock, "Rosenbrock 函数", [0, 0]),
    (himmelblau, "Himmelblau 函数", [0, 0]),
    (sphere, "球面函数", [1, 1]),
    (rastrigin, "Rastrigin 函数", [0.5, 0.5])
]

optimization_methods = [
    'Nelder-Mead',
    'BFGS',
    'CG',
    'Powell',
    'L-BFGS-B'
]

print("\n多变量函数优化结果:")

for func, name, x0 in test_functions:
    print(f"\n{name} (初始点: {x0}):")
    
    for method in optimization_methods:
        try:
            result = optimize.minimize(func, x0, method=method)
            print(f"  {method:12s}: x={result.x}, f(x)={result.fun:.6f}, 迭代次数={result.nit if hasattr(result, 'nit') else 'N/A'}")
        except Exception as e:
            print(f"  {method:12s}: 优化失败 - {str(e)[:50]}")

梯度和海塞矩阵

python
# 定义带梯度的函数
def rosenbrock_with_grad(x):
    """Rosenbrock 函数及其梯度"""
    f = 100 * (x[1] - x[0]**2)**2 + (1 - x[0])**2
    
    # 梯度
    grad = np.zeros(2)
    grad[0] = -400 * x[0] * (x[1] - x[0]**2) - 2 * (1 - x[0])
    grad[1] = 200 * (x[1] - x[0]**2)
    
    return f, grad

def rosenbrock_hess(x):
    """Rosenbrock 函数的海塞矩阵"""
    hess = np.zeros((2, 2))
    hess[0, 0] = -400 * (x[1] - 3 * x[0]**2) + 2
    hess[0, 1] = -400 * x[0]
    hess[1, 0] = -400 * x[0]
    hess[1, 1] = 200
    
    return hess

# 比较使用和不使用梯度的优化效果
x0 = [-1, 1]

print("\n梯度优化比较:")

# 不使用梯度
result_no_grad = optimize.minimize(rosenbrock, x0, method='BFGS')
print(f"不使用梯度: x={result_no_grad.x}, f(x)={result_no_grad.fun:.8f}, 函数调用次数={result_no_grad.nfev}")

# 使用梯度
result_with_grad = optimize.minimize(rosenbrock, x0, method='BFGS', 
                                   jac=lambda x: rosenbrock_with_grad(x)[1])
print(f"使用梯度:   x={result_with_grad.x}, f(x)={result_with_grad.fun:.8f}, 函数调用次数={result_with_grad.nfev}")

# 使用海塞矩阵
result_with_hess = optimize.minimize(rosenbrock, x0, method='Newton-CG',
                                   jac=lambda x: rosenbrock_with_grad(x)[1],
                                   hess=rosenbrock_hess)
print(f"使用海塞矩阵: x={result_with_hess.x}, f(x)={result_with_hess.fun:.8f}, 函数调用次数={result_with_hess.nfev}")

# 可视化优化路径
def plot_optimization_path(func, x0, method='BFGS', bounds=(-2, 2)):
    """可视化优化路径"""
    # 记录优化路径
    path = []
    
    def callback(x):
        path.append(x.copy())
    
    # 优化
    result = optimize.minimize(func, x0, method=method, callback=callback)
    path = np.array(path)
    
    # 绘制等高线和优化路径
    x = np.linspace(bounds[0], bounds[1], 100)
    y = np.linspace(bounds[0], bounds[1], 100)
    X, Y = np.meshgrid(x, y)
    Z = np.zeros_like(X)
    
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Z[i, j] = func([X[i, j], Y[i, j]])
    
    plt.figure(figsize=(10, 8))
    
    # 等高线图
    plt.contour(X, Y, Z, levels=20, alpha=0.6)
    plt.contourf(X, Y, Z, levels=20, alpha=0.3, cmap='viridis')
    
    # 优化路径
    if len(path) > 0:
        plt.plot(path[:, 0], path[:, 1], 'ro-', linewidth=2, markersize=6, 
                label=f'优化路径 ({method})')
        plt.plot(x0[0], x0[1], 'go', markersize=10, label='起始点')
        plt.plot(result.x[0], result.x[1], 'r*', markersize=15, label='最优点')
    
    plt.xlabel('x₁')
    plt.ylabel('x₂')
    plt.title(f'优化路径可视化 - {method}')
    plt.legend()
    plt.colorbar()
    plt.grid(True, alpha=0.3)
    plt.show()
    
    return result, path

# 可视化不同方法的优化路径
for method in ['Nelder-Mead', 'BFGS', 'CG']:
    result, path = plot_optimization_path(rosenbrock, [-1, 1], method)
    print(f"{method}: 迭代次数={len(path)}, 最终值={result.fun:.8f}")

约束优化

1. 等式约束

python
# 定义约束优化问题
# 目标函数: minimize f(x,y) = (x-1)² + (y-2)²
# 约束条件: g(x,y) = x + y - 3 = 0

def objective(x):
    """目标函数"""
    return (x[0] - 1)**2 + (x[1] - 2)**2

def constraint_eq(x):
    """等式约束"""
    return x[0] + x[1] - 3

# 定义约束
cons_eq = {'type': 'eq', 'fun': constraint_eq}

# 初始点
x0 = [0, 0]

# 求解约束优化问题
result_constrained = optimize.minimize(objective, x0, method='SLSQP', constraints=cons_eq)

print("等式约束优化:")
print(f"最优解: x = {result_constrained.x}")
print(f"最优值: f(x) = {result_constrained.fun:.6f}")
print(f"约束值: g(x) = {constraint_eq(result_constrained.x):.6f}")

# 可视化约束优化
x = np.linspace(-1, 4, 100)
y = np.linspace(-1, 4, 100)
X, Y = np.meshgrid(x, y)
Z = (X - 1)**2 + (Y - 2)**2

plt.figure(figsize=(10, 8))

# 等高线图
contour = plt.contour(X, Y, Z, levels=20)
plt.colorbar(contour)

# 约束线
x_constraint = np.linspace(-1, 4, 100)
y_constraint = 3 - x_constraint
plt.plot(x_constraint, y_constraint, 'r-', linewidth=3, label='约束: x + y = 3')

# 无约束最优点
plt.plot(1, 2, 'go', markersize=10, label='无约束最优点 (1, 2)')

# 约束最优点
plt.plot(result_constrained.x[0], result_constrained.x[1], 'ro', markersize=10, 
         label=f'约束最优点 ({result_constrained.x[0]:.2f}, {result_constrained.x[1]:.2f})')

plt.xlabel('x₁')
plt.ylabel('x₂')
plt.title('等式约束优化可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.show()

2. 不等式约束

python
# 定义不等式约束优化问题
# 目标函数: minimize f(x,y) = -x - y
# 约束条件: g₁(x,y) = x² + y² - 1 ≤ 0 (圆形区域内)
#          g₂(x,y) = -x ≤ 0 (x ≥ 0)
#          g₃(x,y) = -y ≤ 0 (y ≥ 0)

def objective_ineq(x):
    """目标函数(最大化 x + y 等价于最小化 -x - y)"""
    return -x[0] - x[1]

def constraint_circle(x):
    """圆形约束"""
    return 1 - x[0]**2 - x[1]**2

def constraint_x_positive(x):
    """x ≥ 0"""
    return x[0]

def constraint_y_positive(x):
    """y ≥ 0"""
    return x[1]

# 定义约束
cons_ineq = [
    {'type': 'ineq', 'fun': constraint_circle},
    {'type': 'ineq', 'fun': constraint_x_positive},
    {'type': 'ineq', 'fun': constraint_y_positive}
]

# 初始点
x0 = [0.5, 0.5]

# 求解约束优化问题
result_ineq = optimize.minimize(objective_ineq, x0, method='SLSQP', constraints=cons_ineq)

print("\n不等式约束优化:")
print(f"最优解: x = {result_ineq.x}")
print(f"最优值: f(x) = {result_ineq.fun:.6f}")
print(f"实际最大值: {-result_ineq.fun:.6f}")
print(f"约束检查:")
print(f"  圆形约束: {constraint_circle(result_ineq.x):.6f} (≥ 0)")
print(f"  x ≥ 0: {constraint_x_positive(result_ineq.x):.6f} (≥ 0)")
print(f"  y ≥ 0: {constraint_y_positive(result_ineq.x):.6f} (≥ 0)")

# 可视化不等式约束优化
theta = np.linspace(0, 2*np.pi, 1000)
circle_x = np.cos(theta)
circle_y = np.sin(theta)

plt.figure(figsize=(10, 8))

# 可行域
theta_feasible = np.linspace(0, np.pi/2, 100)
feasible_x = np.cos(theta_feasible)
feasible_y = np.sin(theta_feasible)
plt.fill_between(feasible_x, 0, feasible_y, alpha=0.3, color='lightblue', label='可行域')

# 约束边界
plt.plot(circle_x, circle_y, 'b-', linewidth=2, label='圆形约束: x² + y² ≤ 1')
plt.axhline(y=0, color='g', linewidth=2, label='y ≥ 0')
plt.axvline(x=0, color='g', linewidth=2, label='x ≥ 0')

# 目标函数等高线
x = np.linspace(-0.2, 1.2, 100)
y = np.linspace(-0.2, 1.2, 100)
X, Y = np.meshgrid(x, y)
Z = -X - Y  # 目标函数
contour = plt.contour(X, Y, Z, levels=10, alpha=0.6, colors='red')
plt.clabel(contour, inline=True, fontsize=8)

# 最优点
plt.plot(result_ineq.x[0], result_ineq.x[1], 'ro', markersize=10, 
         label=f'最优点 ({result_ineq.x[0]:.3f}, {result_ineq.x[1]:.3f})')

plt.xlabel('x₁')
plt.ylabel('x₂')
plt.title('不等式约束优化可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.xlim(-0.2, 1.2)
plt.ylim(-0.2, 1.2)
plt.show()

3. 边界约束

python
# 使用边界约束
# 目标函数: minimize f(x,y) = x² + y²
# 边界约束: -2 ≤ x ≤ 2, -1 ≤ y ≤ 3

def objective_bounds(x):
    return x[0]**2 + x[1]**2

# 定义边界
bounds = [(-2, 2), (-1, 3)]

# 初始点
x0 = [1, 2]

# 求解边界约束优化问题
result_bounds = optimize.minimize(objective_bounds, x0, method='L-BFGS-B', bounds=bounds)

print("\n边界约束优化:")
print(f"最优解: x = {result_bounds.x}")
print(f"最优值: f(x) = {result_bounds.fun:.6f}")

# 可视化边界约束
x = np.linspace(-3, 3, 100)
y = np.linspace(-2, 4, 100)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2

plt.figure(figsize=(10, 8))

# 等高线图
contour = plt.contour(X, Y, Z, levels=20)
plt.colorbar(contour)

# 可行域
rect = plt.Rectangle((-2, -1), 4, 4, fill=False, edgecolor='red', linewidth=3, label='可行域边界')
plt.gca().add_patch(rect)

# 最优点
plt.plot(result_bounds.x[0], result_bounds.x[1], 'ro', markersize=10, 
         label=f'最优点 ({result_bounds.x[0]:.3f}, {result_bounds.x[1]:.3f})')

# 无约束最优点
plt.plot(0, 0, 'go', markersize=10, label='无约束最优点 (0, 0)')

plt.xlabel('x₁')
plt.ylabel('x₂')
plt.title('边界约束优化可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.show()

全局优化

1. 差分进化算法

python
# 使用差分进化算法进行全局优化
# 测试多峰函数

def ackley(x):
    """Ackley 函数(多峰函数)"""
    a, b, c = 20, 0.2, 2*np.pi
    d = len(x)
    sum1 = np.sum(x**2)
    sum2 = np.sum(np.cos(c * x))
    return -a * np.exp(-b * np.sqrt(sum1/d)) - np.exp(sum2/d) + a + np.e

def schwefel(x):
    """Schwefel 函数"""
    return 418.9829 * len(x) - np.sum(x * np.sin(np.sqrt(np.abs(x))))

# 可视化 Ackley 函数
X, Y, Z = plot_2d_function(ackley, (-5, 5), 'Ackley 函数', levels=30)

# 全局优化方法比较
global_functions = [
    (ackley, "Ackley 函数", (-5, 5)),
    (schwefel, "Schwefel 函数", (-500, 500)),
    (rastrigin, "Rastrigin 函数", (-5, 5))
]

print("\n全局优化算法比较:")

for func, name, bounds in global_functions:
    print(f"\n{name}:")
    
    # 差分进化
    bounds_de = [bounds] * 2  # 2维问题
    result_de = optimize.differential_evolution(func, bounds_de, seed=42)
    print(f"  差分进化:     x={result_de.x}, f(x)={result_de.fun:.6f}, 函数调用次数={result_de.nfev}")
    
    # 双重退火
    result_da = optimize.dual_annealing(func, bounds_de, seed=42)
    print(f"  双重退火:     x={result_da.x}, f(x)={result_da.fun:.6f}, 函数调用次数={result_da.nfev}")
    
    # SHGO (Simplicial Homology Global Optimization)
    try:
        result_shgo = optimize.shgo(func, bounds_de)
        print(f"  SHGO:        x={result_shgo.x}, f(x)={result_shgo.fun:.6f}, 函数调用次数={result_shgo.nfev}")
    except:
        print(f"  SHGO:        优化失败")
    
    # 比较局部优化
    x0 = [np.random.uniform(bounds[0], bounds[1]) for _ in range(2)]
    result_local = optimize.minimize(func, x0, method='BFGS')
    print(f"  局部优化(BFGS): x={result_local.x}, f(x)={result_local.fun:.6f}, 函数调用次数={result_local.nfev}")

2. 模拟退火

python
# 自定义模拟退火算法
def simulated_annealing(func, bounds, n_iter=1000, temp_init=100, temp_min=1e-8, alpha=0.95):
    """
    简单的模拟退火算法实现
    """
    # 初始解
    x_current = np.array([np.random.uniform(b[0], b[1]) for b in bounds])
    f_current = func(x_current)
    
    # 最佳解
    x_best = x_current.copy()
    f_best = f_current
    
    # 记录历史
    history = {'x': [x_current.copy()], 'f': [f_current], 'temp': [temp_init]}
    
    temp = temp_init
    
    for i in range(n_iter):
        # 生成邻域解
        x_new = x_current + np.random.normal(0, 0.1, len(x_current))
        
        # 边界处理
        for j, (low, high) in enumerate(bounds):
            x_new[j] = np.clip(x_new[j], low, high)
        
        f_new = func(x_new)
        
        # 接受准则
        if f_new < f_current or np.random.random() < np.exp(-(f_new - f_current) / temp):
            x_current = x_new
            f_current = f_new
            
            # 更新最佳解
            if f_new < f_best:
                x_best = x_new.copy()
                f_best = f_new
        
        # 降温
        temp = max(temp * alpha, temp_min)
        
        # 记录历史
        if i % 10 == 0:
            history['x'].append(x_current.copy())
            history['f'].append(f_current)
            history['temp'].append(temp)
    
    return x_best, f_best, history

# 测试自定义模拟退火
x_best, f_best, history = simulated_annealing(ackley, [(-5, 5), (-5, 5)])

print(f"\n自定义模拟退火结果:")
print(f"最优解: x = {x_best}")
print(f"最优值: f(x) = {f_best:.6f}")

# 可视化模拟退火过程
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 优化路径
history_x = np.array(history['x'])
axes[0, 0].plot(history_x[:, 0], history_x[:, 1], 'o-', alpha=0.7)
axes[0, 0].plot(x_best[0], x_best[1], 'r*', markersize=15, label='最优点')
axes[0, 0].set_xlabel('x₁')
axes[0, 0].set_ylabel('x₂')
axes[0, 0].set_title('优化路径')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 目标函数值变化
axes[0, 1].plot(history['f'])
axes[0, 1].set_xlabel('迭代次数')
axes[0, 1].set_ylabel('目标函数值')
axes[0, 1].set_title('目标函数值变化')
axes[0, 1].grid(True, alpha=0.3)

# 温度变化
axes[1, 0].plot(history['temp'])
axes[1, 0].set_xlabel('迭代次数')
axes[1, 0].set_ylabel('温度')
axes[1, 0].set_title('温度变化')
axes[1, 0].set_yscale('log')
axes[1, 0].grid(True, alpha=0.3)

# 在等高线图上显示路径
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.zeros_like(X)
for i in range(X.shape[0]):
    for j in range(X.shape[1]):
        Z[i, j] = ackley([X[i, j], Y[i, j]])

axes[1, 1].contour(X, Y, Z, levels=20, alpha=0.6)
axes[1, 1].plot(history_x[:, 0], history_x[:, 1], 'ro-', alpha=0.7, markersize=3)
axes[1, 1].plot(x_best[0], x_best[1], 'r*', markersize=15, label='最优点')
axes[1, 1].set_xlabel('x₁')
axes[1, 1].set_ylabel('x₂')
axes[1, 1].set_title('等高线图上的优化路径')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

方程求根

1. 标量方程求根

python
# 定义测试方程
def equation1(x):
    """简单多项式方程: x³ - 2x - 5 = 0"""
    return x**3 - 2*x - 5

def equation2(x):
    """超越方程: e^x - 3x = 0"""
    return np.exp(x) - 3*x

def equation3(x):
    """三角方程: sin(x) - x/2 = 0"""
    return np.sin(x) - x/2

# 可视化方程
x = np.linspace(-3, 3, 1000)

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

equations = [(equation1, "x³ - 2x - 5 = 0"), 
             (equation2, "e^x - 3x = 0"), 
             (equation3, "sin(x) - x/2 = 0")]

for i, (eq, name) in enumerate(equations):
    y = [eq(xi) for xi in x]
    axes[i].plot(x, y, 'b-', linewidth=2)
    axes[i].axhline(y=0, color='r', linestyle='--', alpha=0.7)
    axes[i].set_title(name)
    axes[i].set_xlabel('x')
    axes[i].set_ylabel('f(x)')
    axes[i].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 使用不同方法求根
root_methods = [
    ('brentq', '布伦特方法'),
    ('bisect', '二分法'),
    ('newton', '牛顿法'),
    ('secant', '割线法')
]

print("方程求根结果:")

for eq, eq_name in equations:
    print(f"\n{eq_name}:")
    
    for method, method_name in root_methods:
        try:
            if method in ['brentq', 'bisect']:
                # 需要指定区间
                if eq == equation1:
                    root = optimize.root_scalar(eq, bracket=[1, 3], method=method)
                elif eq == equation2:
                    root = optimize.root_scalar(eq, bracket=[0, 2], method=method)
                else:  # equation3
                    root = optimize.root_scalar(eq, bracket=[0, 2], method=method)
            else:
                # 需要初始猜测
                if eq == equation1:
                    root = optimize.root_scalar(eq, x0=2, method=method)
                elif eq == equation2:
                    root = optimize.root_scalar(eq, x0=1, method=method)
                else:  # equation3
                    root = optimize.root_scalar(eq, x0=1, method=method)
            
            print(f"  {method_name:12s}: x = {root.root:.6f}, f(x) = {eq(root.root):.2e}, 迭代次数 = {root.iterations}")
        except Exception as e:
            print(f"  {method_name:12s}: 求根失败 - {str(e)[:30]}")

2. 非线性方程组

python
# 定义非线性方程组
def equations_system1(vars):
    """方程组1:
    x² + y² = 4
    x - y = 1
    """
    x, y = vars
    eq1 = x**2 + y**2 - 4
    eq2 = x - y - 1
    return [eq1, eq2]

def equations_system2(vars):
    """方程组2:
    x² - y = 1
    x + y² = 2
    """
    x, y = vars
    eq1 = x**2 - y - 1
    eq2 = x + y**2 - 2
    return [eq1, eq2]

def equations_system3(vars):
    """方程组3 (3元):
    x + y + z = 6
    x² + y² + z² = 14
    x³ + y³ + z³ = 36
    """
    x, y, z = vars
    eq1 = x + y + z - 6
    eq2 = x**2 + y**2 + z**2 - 14
    eq3 = x**3 + y**3 + z**3 - 36
    return [eq1, eq2, eq3]

# 求解非线性方程组
systems = [
    (equations_system1, [1, 1], "方程组1 (2元)"),
    (equations_system2, [1, 1], "方程组2 (2元)"),
    (equations_system3, [1, 2, 3], "方程组3 (3元)")
]

print("\n非线性方程组求解:")

for system, x0, name in systems:
    print(f"\n{name}:")
    
    # 使用不同方法
    methods = ['hybr', 'lm', 'broyden1', 'anderson']
    
    for method in methods:
        try:
            sol = optimize.root(system, x0, method=method)
            residual = np.linalg.norm(system(sol.x))
            print(f"  {method:12s}: x = {sol.x}, 残差 = {residual:.2e}, 成功 = {sol.success}")
        except Exception as e:
            print(f"  {method:12s}: 求解失败 - {str(e)[:30]}")

# 可视化二元方程组的解
def plot_system_solution(system_func, solution, title):
    """可视化二元方程组的解"""
    x = np.linspace(-3, 3, 400)
    y = np.linspace(-3, 3, 400)
    X, Y = np.meshgrid(x, y)
    
    # 计算每个方程的零等高线
    Z1 = np.zeros_like(X)
    Z2 = np.zeros_like(X)
    
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            eqs = system_func([X[i, j], Y[i, j]])
            Z1[i, j] = eqs[0]
            Z2[i, j] = eqs[1]
    
    plt.figure(figsize=(10, 8))
    
    # 绘制零等高线
    plt.contour(X, Y, Z1, levels=[0], colors='blue', linewidths=2, label='方程1')
    plt.contour(X, Y, Z2, levels=[0], colors='red', linewidths=2, label='方程2')
    
    # 标记解
    plt.plot(solution[0], solution[1], 'go', markersize=10, 
             label=f'解 ({solution[0]:.3f}, {solution[1]:.3f})')
    
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title(title)
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.axis('equal')
    plt.show()

# 可视化前两个方程组的解
for system, x0, name in systems[:2]:
    sol = optimize.root(system, x0, method='hybr')
    if sol.success:
        plot_system_solution(system, sol.x, f'{name} 的解')

最小二乘拟合

1. 线性最小二乘

python
# 生成带噪声的数据
np.random.seed(42)
n_points = 50
x_data = np.linspace(0, 10, n_points)
y_true = 2 * x_data + 3  # 真实关系: y = 2x + 3
noise = np.random.normal(0, 2, n_points)
y_data = y_true + noise

# 线性最小二乘拟合
def linear_func(x, a, b):
    return a * x + b

# 使用 curve_fit
popt_linear, pcov_linear = optimize.curve_fit(linear_func, x_data, y_data)
a_fit, b_fit = popt_linear

print("线性最小二乘拟合:")
print(f"真实参数: a = 2, b = 3")
print(f"拟合参数: a = {a_fit:.3f}, b = {b_fit:.3f}")
print(f"参数标准误差: {np.sqrt(np.diag(pcov_linear))}")

# 计算拟合优度
y_fit = linear_func(x_data, *popt_linear)
ss_res = np.sum((y_data - y_fit)**2)
ss_tot = np.sum((y_data - np.mean(y_data))**2)
r_squared = 1 - (ss_res / ss_tot)

print(f"R² = {r_squared:.4f}")

# 可视化
plt.figure(figsize=(12, 8))

# 拟合结果
plt.subplot(2, 2, 1)
plt.scatter(x_data, y_data, alpha=0.6, label='观测数据')
plt.plot(x_data, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(x_data, y_fit, 'r-', linewidth=2, label=f'拟合结果 (R²={r_squared:.3f})')
plt.xlabel('x')
plt.ylabel('y')
plt.title('线性最小二乘拟合')
plt.legend()
plt.grid(True, alpha=0.3)

# 残差图
residuals = y_data - y_fit
plt.subplot(2, 2, 2)
plt.scatter(y_fit, residuals, alpha=0.6)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('拟合值')
plt.ylabel('残差')
plt.title('残差图')
plt.grid(True, alpha=0.3)

# 残差直方图
plt.subplot(2, 2, 3)
plt.hist(residuals, bins=15, alpha=0.7, edgecolor='black')
plt.xlabel('残差')
plt.ylabel('频数')
plt.title('残差分布')
plt.grid(True, alpha=0.3)

# Q-Q 图
from scipy import stats
stats.probplot(residuals, dist="norm", plot=plt.subplot(2, 2, 4))
plt.title('残差 Q-Q 图')
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

2. 非线性最小二乘

python
# 生成非线性数据
np.random.seed(42)
x_data = np.linspace(0, 4, 50)
y_true = 3 * np.exp(-2 * x_data) + 1  # 真实关系: y = 3*exp(-2x) + 1
noise = np.random.normal(0, 0.1, len(x_data))
y_data = y_true + noise

# 定义非线性函数
def exponential_func(x, a, b, c):
    return a * np.exp(-b * x) + c

def gaussian_func(x, a, b, c):
    return a * np.exp(-(x - b)**2 / (2 * c**2))

def polynomial_func(x, a, b, c, d):
    return a * x**3 + b * x**2 + c * x + d

# 非线性拟合
functions = [
    (exponential_func, [1, 1, 1], "指数函数"),
    (gaussian_func, [1, 2, 1], "高斯函数"),
    (polynomial_func, [1, 1, 1, 1], "三次多项式")
]

print("\n非线性最小二乘拟合:")

fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()

# 原始数据
axes[0].scatter(x_data, y_data, alpha=0.6, label='观测数据')
axes[0].plot(x_data, y_true, 'g-', linewidth=2, label='真实关系')
axes[0].set_xlabel('x')
axes[0].set_ylabel('y')
axes[0].set_title('原始数据')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

for i, (func, p0, name) in enumerate(functions):
    try:
        popt, pcov = optimize.curve_fit(func, x_data, y_data, p0=p0)
        y_fit = func(x_data, *popt)
        
        # 计算拟合优度
        ss_res = np.sum((y_data - y_fit)**2)
        ss_tot = np.sum((y_data - np.mean(y_data))**2)
        r_squared = 1 - (ss_res / ss_tot)
        
        print(f"\n{name}:")
        print(f"  拟合参数: {popt}")
        print(f"  参数标准误差: {np.sqrt(np.diag(pcov))}")
        print(f"  R² = {r_squared:.4f}")
        
        # 可视化
        axes[i+1].scatter(x_data, y_data, alpha=0.6, label='观测数据')
        axes[i+1].plot(x_data, y_true, 'g-', linewidth=2, label='真实关系')
        axes[i+1].plot(x_data, y_fit, 'r-', linewidth=2, 
                      label=f'{name} (R²={r_squared:.3f})')
        axes[i+1].set_xlabel('x')
        axes[i+1].set_ylabel('y')
        axes[i+1].set_title(f'{name} 拟合')
        axes[i+1].legend()
        axes[i+1].grid(True, alpha=0.3)
        
    except Exception as e:
        print(f"\n{name}: 拟合失败 - {str(e)}")

plt.tight_layout()
plt.show()

3. 鲁棒回归

python
# 生成带异常值的数据
np.random.seed(42)
n_points = 50
x_data = np.linspace(0, 10, n_points)
y_true = 2 * x_data + 3
noise = np.random.normal(0, 1, n_points)
y_data = y_true + noise

# 添加异常值
outlier_indices = [10, 25, 40]
for idx in outlier_indices:
    y_data[idx] += np.random.choice([-8, 8])

# 定义损失函数
def huber_loss(params, x, y, delta=1.0):
    """Huber 损失函数"""
    a, b = params
    residuals = y - (a * x + b)
    
    # Huber 损失
    loss = np.where(np.abs(residuals) <= delta,
                   0.5 * residuals**2,
                   delta * (np.abs(residuals) - 0.5 * delta))
    return np.sum(loss)

def least_squares_loss(params, x, y):
    """最小二乘损失函数"""
    a, b = params
    residuals = y - (a * x + b)
    return np.sum(residuals**2)

# 比较不同的拟合方法
print("\n鲁棒回归比较:")

# 普通最小二乘
result_ols = optimize.minimize(least_squares_loss, [1, 1], args=(x_data, y_data))
a_ols, b_ols = result_ols.x
y_fit_ols = a_ols * x_data + b_ols

# Huber 回归
result_huber = optimize.minimize(huber_loss, [1, 1], args=(x_data, y_data, 1.0))
a_huber, b_huber = result_huber.x
y_fit_huber = a_huber * x_data + b_huber

# 使用 scipy 的鲁棒方法
from scipy.optimize import least_squares

def residuals_func(params, x, y):
    a, b = params
    return y - (a * x + b)

# 普通最小二乘
result_ls = least_squares(residuals_func, [1, 1], args=(x_data, y_data))
a_ls, b_ls = result_ls.x
y_fit_ls = a_ls * x_data + b_ls

# 鲁棒最小二乘 (soft_l1 损失)
result_robust = least_squares(residuals_func, [1, 1], args=(x_data, y_data), loss='soft_l1')
a_robust, b_robust = result_robust.x
y_fit_robust = a_robust * x_data + b_robust

print(f"真实参数:     a = 2.000, b = 3.000")
print(f"普通最小二乘: a = {a_ols:.3f}, b = {b_ols:.3f}")
print(f"Huber 回归:   a = {a_huber:.3f}, b = {b_huber:.3f}")
print(f"鲁棒最小二乘: a = {a_robust:.3f}, b = {b_robust:.3f}")

# 可视化比较
plt.figure(figsize=(15, 5))

# 原始数据
plt.subplot(1, 3, 1)
plt.scatter(x_data, y_data, alpha=0.6, label='观测数据')
for idx in outlier_indices:
    plt.scatter(x_data[idx], y_data[idx], color='red', s=100, marker='x', label='异常值' if idx == outlier_indices[0] else "")
plt.plot(x_data, y_true, 'g-', linewidth=2, label='真实关系')
plt.xlabel('x')
plt.ylabel('y')
plt.title('带异常值的数据')
plt.legend()
plt.grid(True, alpha=0.3)

# 拟合结果比较
plt.subplot(1, 3, 2)
plt.scatter(x_data, y_data, alpha=0.6, label='观测数据')
for idx in outlier_indices:
    plt.scatter(x_data[idx], y_data[idx], color='red', s=100, marker='x')
plt.plot(x_data, y_true, 'g-', linewidth=2, label='真实关系')
plt.plot(x_data, y_fit_ols, 'b--', linewidth=2, label='普通最小二乘')
plt.plot(x_data, y_fit_robust, 'r-', linewidth=2, label='鲁棒回归')
plt.xlabel('x')
plt.ylabel('y')
plt.title('拟合结果比较')
plt.legend()
plt.grid(True, alpha=0.3)

# 残差比较
residuals_ols = y_data - y_fit_ols
residuals_robust = y_data - y_fit_robust

plt.subplot(1, 3, 3)
plt.scatter(y_fit_ols, residuals_ols, alpha=0.6, label='普通最小二乘')
plt.scatter(y_fit_robust, residuals_robust, alpha=0.6, label='鲁棒回归')
plt.axhline(y=0, color='k', linestyle='--')
plt.xlabel('拟合值')
plt.ylabel('残差')
plt.title('残差比较')
plt.legend()
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

线性规划

python
# 线性规划问题
# 目标函数: maximize 3x₁ + 2x₂
# 约束条件: x₁ + x₂ ≤ 4
#          2x₁ + x₂ ≤ 6
#          x₁, x₂ ≥ 0

from scipy.optimize import linprog

# 定义线性规划问题(注意:linprog 求最小值,所以目标函数系数要取负)
c = [-3, -2]  # 目标函数系数(取负号因为要最大化)
A_ub = [[1, 1],   # 不等式约束矩阵
        [2, 1]]
b_ub = [4, 6]     # 不等式约束右端
bounds = [(0, None), (0, None)]  # 变量边界

# 求解线性规划
result_lp = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')

print("\n线性规划求解结果:")
print(f"最优解: x₁ = {result_lp.x[0]:.3f}, x₂ = {result_lp.x[1]:.3f}")
print(f"最优值: {-result_lp.fun:.3f}")  # 取负号因为原问题是最大化
print(f"求解状态: {result_lp.message}")

# 可视化线性规划
x1 = np.linspace(0, 5, 400)
x2 = np.linspace(0, 5, 400)
X1, X2 = np.meshgrid(x1, x2)

plt.figure(figsize=(10, 8))

# 可行域
# 约束1: x₁ + x₂ ≤ 4
x2_constraint1 = 4 - x1
# 约束2: 2x₁ + x₂ ≤ 6
x2_constraint2 = 6 - 2*x1

# 绘制约束线
plt.plot(x1, x2_constraint1, 'b-', linewidth=2, label='x₁ + x₂ ≤ 4')
plt.plot(x1, x2_constraint2, 'r-', linewidth=2, label='2x₁ + x₂ ≤ 6')
plt.axhline(y=0, color='k', linewidth=1)
plt.axvline(x=0, color='k', linewidth=1)

# 填充可行域
feasible_x1 = np.linspace(0, 3, 100)
feasible_x2_upper = np.minimum(4 - feasible_x1, 6 - 2*feasible_x1)
feasible_x2_upper = np.maximum(feasible_x2_upper, 0)
plt.fill_between(feasible_x1, 0, feasible_x2_upper, alpha=0.3, color='lightblue', label='可行域')

# 目标函数等高线
Z = 3*X1 + 2*X2
contour = plt.contour(X1, X2, Z, levels=10, alpha=0.6, colors='green')
plt.clabel(contour, inline=True, fontsize=8)

# 最优点
plt.plot(result_lp.x[0], result_lp.x[1], 'ro', markersize=10, 
         label=f'最优点 ({result_lp.x[0]:.2f}, {result_lp.x[1]:.2f})')

plt.xlabel('x₁')
plt.ylabel('x₂')
plt.title('线性规划可视化')
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(0, 5)
plt.ylim(0, 5)
plt.show()

实际应用案例

1. 投资组合优化

python
# 投资组合优化问题
# 假设有3只股票,历史收益率数据
np.random.seed(42)
n_assets = 3
n_periods = 252  # 一年的交易日

# 生成模拟的收益率数据
returns = np.random.multivariate_normal(
    mean=[0.08, 0.12, 0.15],  # 年化收益率
    cov=[[0.04, 0.01, 0.02],  # 协方差矩阵
         [0.01, 0.09, 0.03],
         [0.02, 0.03, 0.16]],
    size=n_periods
) / np.sqrt(252)  # 转换为日收益率

# 计算统计量
mean_returns = np.mean(returns, axis=0)
cov_matrix = np.cov(returns.T)

print("投资组合优化:")
print(f"预期收益率: {mean_returns * 252:.3f}")  # 年化
print(f"协方差矩阵:\n{cov_matrix * 252:.4f}")  # 年化

# 定义优化问题
def portfolio_variance(weights, cov_matrix):
    """投资组合方差"""
    return np.dot(weights.T, np.dot(cov_matrix, weights))

def portfolio_return(weights, mean_returns):
    """投资组合收益率"""
    return np.dot(weights, mean_returns)

# 约束条件
constraints = [
    {'type': 'eq', 'fun': lambda x: np.sum(x) - 1}  # 权重和为1
]

# 边界条件(权重在0-1之间)
bounds = tuple((0, 1) for _ in range(n_assets))

# 初始猜测
x0 = np.array([1/n_assets] * n_assets)

# 最小方差组合
result_min_var = optimize.minimize(
    portfolio_variance, x0, args=(cov_matrix,),
    method='SLSQP', bounds=bounds, constraints=constraints
)

min_var_weights = result_min_var.x
min_var_return = portfolio_return(min_var_weights, mean_returns) * 252
min_var_risk = np.sqrt(portfolio_variance(min_var_weights, cov_matrix) * 252)

print(f"\n最小方差组合:")
print(f"权重: {min_var_weights}")
print(f"年化收益率: {min_var_return:.3f}")
print(f"年化波动率: {min_var_risk:.3f}")

# 有效前沿
target_returns = np.linspace(min_var_return, 0.20, 50)
efficient_portfolios = []

for target in target_returns:
    # 添加收益率约束
    cons = [
        {'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
        {'type': 'eq', 'fun': lambda x, target=target: portfolio_return(x, mean_returns) * 252 - target}
    ]
    
    result = optimize.minimize(
        portfolio_variance, x0, args=(cov_matrix,),
        method='SLSQP', bounds=bounds, constraints=cons
    )
    
    if result.success:
        risk = np.sqrt(portfolio_variance(result.x, cov_matrix) * 252)
        efficient_portfolios.append((target, risk, result.x))

# 可视化有效前沿
if efficient_portfolios:
    returns_eff = [p[0] for p in efficient_portfolios]
    risks_eff = [p[1] for p in efficient_portfolios]
    
    plt.figure(figsize=(10, 8))
    plt.plot(risks_eff, returns_eff, 'b-', linewidth=2, label='有效前沿')
    plt.scatter(min_var_risk, min_var_return, color='red', s=100, 
                label=f'最小方差组合\n(收益率={min_var_return:.3f}, 风险={min_var_risk:.3f})')
    
    # 单个资产
    for i in range(n_assets):
        asset_return = mean_returns[i] * 252
        asset_risk = np.sqrt(cov_matrix[i, i] * 252)
        plt.scatter(asset_risk, asset_return, s=100, label=f'资产 {i+1}')
    
    plt.xlabel('风险 (年化波动率)')
    plt.ylabel('收益率 (年化)')
    plt.title('投资组合有效前沿')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

2. 生产计划优化

python
# 生产计划优化问题
# 某工厂生产两种产品,需要优化生产计划

# 问题参数
profit = [40, 30]  # 每单位产品的利润
labor_hours = [2, 1]  # 每单位产品需要的工时
material_cost = [10, 8]  # 每单位产品的材料成本

# 约束条件
max_labor = 100  # 最大工时
max_material_budget = 800  # 最大材料预算
min_product1 = 10  # 产品1的最小产量
max_product2 = 50  # 产品2的最大产量

# 定义优化问题
def production_profit(x):
    """负利润(因为要最大化利润)"""
    return -(profit[0] * x[0] + profit[1] * x[1])

# 约束函数
def labor_constraint(x):
    return max_labor - (labor_hours[0] * x[0] + labor_hours[1] * x[1])

def material_constraint(x):
    return max_material_budget - (material_cost[0] * x[0] + material_cost[1] * x[1])

def min_product1_constraint(x):
    return x[0] - min_product1

def max_product2_constraint(x):
    return max_product2 - x[1]

# 定义约束
constraints_prod = [
    {'type': 'ineq', 'fun': labor_constraint},
    {'type': 'ineq', 'fun': material_constraint},
    {'type': 'ineq', 'fun': min_product1_constraint},
    {'type': 'ineq', 'fun': max_product2_constraint}
]

# 边界条件
bounds_prod = [(0, None), (0, None)]

# 初始猜测
x0_prod = [20, 30]

# 求解
result_prod = optimize.minimize(
    production_profit, x0_prod,
    method='SLSQP', bounds=bounds_prod, constraints=constraints_prod
)

optimal_production = result_prod.x
max_profit = -result_prod.fun

print("\n生产计划优化结果:")
print(f"最优生产计划: 产品1 = {optimal_production[0]:.1f} 单位, 产品2 = {optimal_production[1]:.1f} 单位")
print(f"最大利润: {max_profit:.2f}")

# 检查约束
print(f"\n约束检查:")
print(f"工时使用: {labor_hours[0] * optimal_production[0] + labor_hours[1] * optimal_production[1]:.1f} / {max_labor}")
print(f"材料成本: {material_cost[0] * optimal_production[0] + material_cost[1] * optimal_production[1]:.1f} / {max_material_budget}")
print(f"产品1产量: {optimal_production[0]:.1f} (≥ {min_product1})")
print(f"产品2产量: {optimal_production[1]:.1f} (≤ {max_product2})")

性能优化技巧

1. 选择合适的算法

python
# 比较不同算法的性能
import time

def benchmark_optimization_methods():
    """基准测试不同优化方法的性能"""
    
    # 测试函数
    test_functions = [
        (rosenbrock, [-1, 1], "Rosenbrock"),
        (himmelblau, [0, 0], "Himmelblau"),
        (ackley, [1, 1], "Ackley")
    ]
    
    methods = ['Nelder-Mead', 'BFGS', 'CG', 'Powell', 'L-BFGS-B']
    
    results = {}
    
    for func, x0, func_name in test_functions:
        print(f"\n{func_name} 函数性能测试:")
        results[func_name] = {}
        
        for method in methods:
            try:
                start_time = time.time()
                result = optimize.minimize(func, x0, method=method)
                end_time = time.time()
                
                results[func_name][method] = {
                    'time': end_time - start_time,
                    'fun_value': result.fun,
                    'nfev': result.nfev if hasattr(result, 'nfev') else 'N/A',
                    'success': result.success
                }
                
                print(f"  {method:12s}: 时间={end_time - start_time:.4f}s, "
                      f"函数值={result.fun:.6f}, 调用次数={result.nfev if hasattr(result, 'nfev') else 'N/A'}")
                      
            except Exception as e:
                print(f"  {method:12s}: 失败 - {str(e)[:30]}")
    
    return results

# 运行基准测试
benchmark_results = benchmark_optimization_methods()

2. 并行优化

python
# 并行全局优化
from concurrent.futures import ProcessPoolExecutor
import multiprocessing

def parallel_optimization(func, bounds, n_trials=10, n_processes=None):
    """并行运行多次优化"""
    
    if n_processes is None:
        n_processes = multiprocessing.cpu_count()
    
    def single_optimization(seed):
        np.random.seed(seed)
        x0 = [np.random.uniform(b[0], b[1]) for b in bounds]
        result = optimize.minimize(func, x0, method='L-BFGS-B', bounds=bounds)
        return result.x, result.fun, result.success
    
    # 并行执行
    with ProcessPoolExecutor(max_workers=n_processes) as executor:
        futures = [executor.submit(single_optimization, i) for i in range(n_trials)]
        results = [future.result() for future in futures]
    
    # 找到最佳结果
    successful_results = [r for r in results if r[2]]  # 只考虑成功的结果
    
    if successful_results:
        best_result = min(successful_results, key=lambda x: x[1])
        return best_result[0], best_result[1], len(successful_results)
    else:
        return None, None, 0

# 测试并行优化
print("\n并行优化测试:")
start_time = time.time()
best_x, best_f, n_success = parallel_optimization(ackley, [(-5, 5), (-5, 5)], n_trials=20)
end_time = time.time()

if best_x is not None:
    print(f"最佳解: x = {best_x}")
    print(f"最佳值: f(x) = {best_f:.6f}")
    print(f"成功次数: {n_success}/20")
    print(f"总时间: {end_time - start_time:.2f}s")
else:
    print("所有优化尝试都失败了")

小结

本章详细介绍了 SciPy 的优化算法模块 scipy.optimize,包括:

  1. 标量函数优化:单变量和多变量函数的最小值/最大值求解
  2. 约束优化:等式约束、不等式约束和边界约束的处理
  3. 全局优化:差分进化、模拟退火等全局搜索算法
  4. 方程求根:标量方程和非线性方程组的求解
  5. 最小二乘拟合:线性和非线性参数估计,鲁棒回归
  6. 线性规划:线性目标函数和约束的优化问题
  7. 实际应用:投资组合优化、生产计划等实际案例
  8. 性能优化:算法选择和并行计算技巧

优化算法是科学计算和工程应用中的核心工具,掌握这些方法对于解决实际问题具有重要意义。

练习题

  1. 实现一个遗传算法来优化 Rastrigin 函数,并与 SciPy 的差分进化算法比较性能。

  2. 设计一个多目标优化问题,同时最小化成本和最大化质量,使用约束优化方法求解。

  3. 对一组实验数据进行非线性拟合,比较不同损失函数(最小二乘、Huber、绝对值)的效果。

  4. 实现一个简单的投资组合优化器,考虑交易成本和最小持仓限制。

  5. 使用线性规划解决一个运输问题:从多个供应点向多个需求点运输货物,最小化总运输成本。

本站内容仅供学习和研究使用。