如何用Scipy.minimise求解元素仅为-1或1的最优整数数组
问题解答
能否直接使用scipy.minimize()实现?
不能。scipy.minimize()内置的主流求解器(如SLSQP、L-BFGS-B、BFGS等)均面向连续变量优化场景设计,无法原生支持变量仅取-1、1的离散约束,直接调用会得到连续域的浮点解,不符合你的需求。
可行实现方案
下面提供两种适配不同场景的实现方案:
方案1:暴力枚举(适用于x长度≤20的场景)
你的示例中x长度仅为5,总共有2^5=32种可能的取值组合,暴力遍历所有情况既快又能保证得到全局最优解,是当前场景的最优选择。
代码示例:
import random import itertools data = random.sample(range(1, 100), 5) def f(x, data): prod = [a * b for a, b in zip(data, x)] return abs(sum(prod)) # 生成所有可能的x组合(元素仅为-1或1) all_x = itertools.product([-1, 1], repeat=len(data)) # 遍历找最优解 min_f = float('inf') best_x = None for x in all_x: current_f = f(x, data) if current_f < min_f: min_f = current_f best_x = x # 最优可能为0,找到即可提前退出 if min_f == 0: break print(f"最优x:{best_x}") print(f"最小f(x):{min_f}")
方案2:启发式全局优化(适用于x长度较大的场景)
如果x长度超过20,暴力枚举算力不足,可以用scipy.optimize.differential_evolution(差分进化算法)实现,它支持整数约束,我们可以通过变量转换满足-1/1的取值要求:
令中间变量y为仅取0、1的整数变量,那么x = 2*y -1自然仅能取-1、1,无需额外约束。
代码示例:
import random from scipy.optimize import differential_evolution data = random.sample(range(1, 100), 5) n = len(data) def f(y, data): x = 2 * y - 1 # 转换为-1/1的x prod = [a * b for a, b in zip(data, x)] return abs(sum(prod)) # 每个y的取值边界是0到1,且为整数 bounds = [(0, 1)] * n # integrality参数标记所有变量为整数类型 res = differential_evolution(f, bounds, args=(data,), integrality=[True]*n, seed=42) best_y = res.x best_x = 2 * best_y - 1 min_f = res.fun print(f"最优x:{best_x}") print(f"最小f(x):{min_f}")
注意:差分进化是启发式算法,不保证100%得到全局最优解,可通过调整
popsize、maxiter等参数提升求解效果。
其他可选方案
如果x长度很大且对最优性要求高,可以使用专门的整数规划求解库(如PuLP、OR-Tools)建模求解0-1整数规划问题,精度和效率会优于通用启发式算法。
内容的提问来源于stack exchange,提问作者Thomas LESIEUR
相关产品推荐
相关产品推荐

