Scipy/Facile优化逻辑构建求助:求和优化代码实现困惑
针对你的组合优化问题的解决方案
先帮你把问题拆解清楚,这本质是个0-1整数线性规划问题——选或不选某一行是二元决策,还要满足各表格的选行数量约束,刚好能用scipy的优化工具解决。下面结合建模思路和代码示例给你讲透:
第一步:把问题转化为数学模型
假设你有5个表格A、B、C、D、E,分别有n_A、n_B、n_C、n_D、n_E行。我们给每一行分配一个0-1变量:
- A的第i行对应变量
x_Ai,选则为1,不选为0 - B的第j行对应变量
x_Bj,以此类推
目标函数
假设你要优化的是选中行的某个指标之和(比如每行的成本、收益),比如最小化这个和:
总目标 = sum(x_Ai * 行i的指标值) + sum(x_Bj * 行j的指标值) + ... + sum(x_Em * 行m的指标值)
如果是最大化,只需要把目标函数取反(因为scipy工具默认求最小)。
约束条件
- 各表格的选行数量要求:
- A选2行:
sum(x_A1, x_A2, ..., x_AnA) = 2 - B选3行:
sum(x_B1, x_B2, ..., x_BnB) = 3 - C选2行:
sum(x_C1, ..., x_CnC) = 2 - D选1行:
sum(x_D1, ..., x_DnD) = 1 - E选1行:
sum(x_E1, ..., x_EnE) = 1
- A选2行:
- 所有变量只能是0或1:
x_xxx ∈ {0,1}
第二步:用scipy.linprog实现(推荐,scipy 1.9+支持)
直接上可运行的示例代码,你可以替换成自己的表格数据:
import numpy as np from scipy.optimize import linprog # ---------------------- 替换成你的实际数据 ---------------------- # 每个表格的行对应的待优化指标值(比如成本、收益) A_vals = [1.2, 3.1, 2.5, 4.0] # A有4行,要选2行 B_vals = [0.8, 1.5, 2.2, 3.0, 0.5] # B有5行,要选3行 C_vals = [5.0, 2.3, 1.8] # C有3行,要选2行 D_vals = [3.5, 2.8] # D有2行,要选1行 E_vals = [4.2, 1.9] # E有2行,要选1行 # -------------------------------------------------------------- # 1. 构建目标函数系数数组c(把所有行的指标值合并成一维) c = np.concatenate([A_vals, B_vals, C_vals, D_vals, E_vals]) # 2. 构建约束条件的等式矩阵A_eq和右端向量b_eq n_A, n_B, n_C, n_D, n_E = len(A_vals), len(B_vals), len(C_vals), len(D_vals), len(E_vals) total_vars = len(c) # 每个约束对应一行,只有对应表格的变量位置为1 constraint_A = np.zeros(total_vars) constraint_A[:n_A] = 1 # A的变量在最前面 constraint_B = np.zeros(total_vars) constraint_B[n_A:n_A+n_B] = 1 constraint_C = np.zeros(total_vars) constraint_C[n_A+n_B:n_A+n_B+n_C] = 1 constraint_D = np.zeros(total_vars) constraint_D[n_A+n_B+n_C:n_A+n_B+n_C+n_D] = 1 constraint_E = np.zeros(total_vars) constraint_E[-n_E:] = 1 # E的变量在最后 A_eq = np.vstack([constraint_A, constraint_B, constraint_C, constraint_D, constraint_E]) b_eq = np.array([2, 3, 2, 1, 1]) # 对应各表格的选行数量 # 3. 设置变量边界:每个变量只能是0或1 bounds = [(0, 1)] * total_vars # 4. 求解整数规划 result = linprog( c=c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs', # 必须用支持整数约束的方法 integrality=np.ones(total_vars) # 所有变量都是整数(0或1) ) # 5. 解析结果 if result.success: print("✅ 优化成功!") x = result.x.round() # 浮点数结果转0-1整数 # 提取每个表格选中的行索引 selected_A = np.where(x[:n_A] == 1)[0] selected_B = np.where(x[n_A:n_A+n_B] == 1)[0] selected_C = np.where(x[n_A+n_B:n_A+n_B+n_C] == 1)[0] selected_D = np.where(x[n_A+n_B+n_C:n_A+n_B+n_C+n_D] == 1)[0] selected_E = np.where(x[-n_E:] == 1)[0] print(f"A选中的行索引:{selected_A}") print(f"B选中的行索引:{selected_B}") print(f"C选中的行索引:{selected_C}") print(f"D选中的行索引:{selected_D}") print(f"E选中的行索引:{selected_E}") print(f"目标函数最终值:{result.fun:.2f}") else: print("❌ 优化失败,原因:", result.message)
第三步:关键细节说明
- 最大化需求处理:如果要最大化指标和,只需把
c改成-c,最后把result.fun取反即可。 - 低版本scipy兼容:如果你的scipy版本低于1.9,无法使用
linprog的integrality参数,可以改用scipy.optimize.minimize配合整数约束:from scipy.optimize import minimize, LinearConstraint, Bounds def objective(x): return np.dot(x, c) # 最大化的话返回 -np.dot(x, c) linear_constraint = LinearConstraint(A_eq, b_eq, b_eq) bounds = Bounds([0]*total_vars, [1]*total_vars) x0 = np.zeros(total_vars) # 初始猜测值 result = minimize( objective, x0=x0, method='trust-constr', bounds=bounds, constraints=[linear_constraint], integrality=np.ones(total_vars) ) - 无解排查:如果优化失败,先检查表格行数是否满足选行要求(比如A只有1行却要求选2行,肯定无解)。
内容的提问来源于stack exchange,提问作者tyu0912
相关产品推荐
相关产品推荐

