Scipy优化中高效实现多约束:用稀疏线性约束替代循环查找

秋强小哥_2716

秋强小哥_2716

2026-07-18

826人浏览

原创

Scipy优化中高效实现多约束:用稀疏线性约束替代循环查找

本文介绍如何将22个硬编码索引的不等式约束,通过稀疏csr矩阵一次性高效表达,避免运行时重复查找与数据转换,使约束评估速度提升10倍以上,并保持配置灵活性。

本文介绍如何将22个硬编码索引的不等式约束,通过稀疏csr矩阵一次性高效表达,避免运行时重复查找与数据转换,使约束评估速度提升10倍以上,并保持配置灵活性。

在使用 scipy.optimize(尤其是 trust-constr 或 SLSQP)进行大规模参数优化时,约束函数的执行效率直接影响整体求解性能。您当前遇到的问题非常典型:将22个独立、结构一致的线性不等式约束(形如 ∑(parameters[i:j]) ≤ C)封装为一个通用函数后,运行时间暴增10倍——根本原因在于每次调用都触发了低效的运行时操作:np.where() 全量扫描、DataFrame 索引查找、.loc 动态查询、多次 .values[0][0] 解包等,这些操作在每次梯度/雅可比计算中被反复执行(每轮迭代可能调用数百次),形成严重瓶颈。

而原始硬编码版本虽可读性差、维护成本高,却因完全避免动态查找、仅用原生 NumPy 切片与标量运算,达到了极致的执行效率。幸运的是,无需二者取舍:Scipy 提供了专为线性约束设计的高性能接口 LinearConstraint,配合稀疏矩阵表示,可同时兼顾速度、可维护性与清晰性。

✅ 推荐方案:使用 LinearConstraint + 稀疏 CSR 矩阵

所有约束本质均为线性不等式:A @ x ≤ ub。其中:

  • x 是 75 维参数向量;
  • 每行 A[i] 是一个 0-1 向量,仅在对应索引位置为 1(表示参与求和的变量);
  • ub 是长度为 22 的上界数组(即 [129, 2571, ..., 4286])。

利用 scipy.sparse.csr_array 构建稀疏约束矩阵,可将内存占用降至最低,并使矩阵乘法 A @ x 以接近 C 层级的速度完成(仅对非零元运算,复杂度 O(nnz)),远快于 Python 循环或 Pandas 查找。

? 实现步骤(完整可运行示例)

import numpy as np
from scipy.optimize import minimize, LinearConstraint
import scipy.sparse

# Step 1: 定义每组参数的起始/结束索引(按原始约束顺序)
# 例如:[0:2], [2:5], [5:8], ... → 对应切片边界点
slice_boundaries = [
    0, 2, 5, 8, 10, 13, 16, 21, 25, 28,
    30, 33, 38, 43, 45, 47, 51, 53, 57,
    64, 67, 72, 75
]

# Step 2: 构建稀疏约束矩阵 A (22 × 75)
# data: 全为 1.0(每个约束中参与求和的变量权重为 1)
# indices: 所有非零元素的列索引(即参数下标)
# indptr: CSR 格式指针数组,长度为 (n_constraints + 1)
data = np.ones(sum(slice_boundaries[i+1] - slice_boundaries[i] 
                   for i in range(len(slice_boundaries)-1)))
indices = np.concatenate([
    np.arange(slice_boundaries[i], slice_boundaries[i+1])
    for i in range(len(slice_boundaries)-1)
])
indptr = np.array([0] + list(np.cumsum([
    slice_boundaries[i+1] - slice_boundaries[i] 
    for i in range(len(slice_boundaries)-1)
]))

A = scipy.sparse.csr_array((data, indices, indptr), shape=(22, 75))

# Step 3: 定义上界向量 ub
ub = np.array([
    129, 2571, 3857, 823, 823, 3857, 4714, 3429, 3429, 3429,
    2914, 6000, 6000, 429, 1457, 4286, 2143, 4286, 2143, 2571,
    1714, 4286
])

# Step 4: 创建 LinearConstraint 对象(推荐!)
constraint = LinearConstraint(A=A, ub=ub)

# Step 5: 替换原有 constraints 列表
constraints = [constraint]  # 单个 LinearConstraint 即代表全部 22 个不等式

# ⚠️ 注意:bounds 和 objective function 保持不变
bounds = tuple((0, 10000) for _ in range(75))
x0 = np.full(75, 10000.0)

result = minimize(
    fun=ObjectiveFunction,
    x0=x0,
    method='trust-constr',
    bounds=bounds,
    constraints=constraints,  # ← 使用高效线性约束
    options={'maxiter': 1000}
)

? 关键优势与注意事项

  • 性能飞跃:A @ x 在稀疏 CSR 下平均耗时 100 μs/次),提速 10×+,且随约束数增长优势更明显。
  • 配置解耦:ub 数组和 slice_boundaries 可直接从 CSV/JSON 加载,无需修改代码逻辑,真正实现“数据驱动约束”。
  • 内存友好:75×22 的稠密矩阵需约 13 KB,而 CSR 存储仅需 ~3 KB(仅存非零值及索引)。
  • 兼容性保障:LinearConstraint 被 trust-constr 原生支持,自动提供精确雅可比,显著提升收敛稳定性与速度。
  • ⚠️ 重要提醒:
    • 确保 ObjectiveFunction 返回标量(非数组);
    • 若需等式约束,可用 LinearConstraint(A, lb=..., ub=...);
    • 避免在 LinearConstraint 外层再包裹 Python 函数(如 fun=lambda x: A@x),这会失去稀疏加速优势。

✅ 总结

放弃“通用约束函数 + 运行时查找”的设计,转而采用 LinearConstraint + 稀疏矩阵,是 Scipy 线性约束场景下的标准最佳实践。它不仅彻底解决性能瓶颈,还将约束逻辑从代码中剥离,交由结构化数据管理,大幅提升可维护性与扩展性。对于含数十乃至上百个同类线性约束的优化问题,此方案应作为默认选择。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1651

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4124

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1669

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

23877

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2927

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2947

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1143

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2283

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习