如何用Python(含Gekko)求解多矩阵多约束变量分配问题
Python 财务预算分配线性规划解决方案
适用工具与库
- Pandas:负责Excel数据的读取、清洗、维度整理与结果输出
- Gekko:求解大规模线性/非线性规划问题,适配复杂约束场景
- NumPy:辅助矩阵运算(可选,用于数据维度校验)
核心模型思路
将问题转化为线性规划问题:
- 决策变量:
x[国家, 季度, 产品线],即每个维度组合的预算分配值 - 约束条件:严格对应题目中的4项要求
- 目标函数:最小化所有分配值总和与年度总预算目标的偏差,满足99%精度要求
代码实现步骤
1. 数据读取与预处理(Pandas)
假设你的Excel文件包含4个工作表,分别存储季度预算、年度目标、季节性约束和总预算目标:
import pandas as pd from gekko import GEKKO # 读取数据 quarter_budgets = pd.read_excel('budget_data.xlsx', sheet_name='quarter_budgets', index_col='Country') annual_targets = pd.read_excel('budget_data.xlsx', sheet_name='annual_targets', index_col=['Country', 'Product']) seasonal_constraints = pd.read_excel('budget_data.xlsx', sheet_name='seasonal_constraints', index_col='Product') total_budget_target = pd.read_excel('budget_data.xlsx', sheet_name='total_budget_target').iloc[0, 0] # 整理维度列表 countries = quarter_budgets.index.unique().tolist() quarters = quarter_budgets.columns.tolist() products = annual_targets.index.get_level_values('Product').unique().tolist()
2. 初始化Gekko求解器
m = GEKKO(remote=False) # 本地运行,适配大规模变量场景
3. 创建决策变量
# 构建三维字典存储决策变量,所有值非负 x = {} for c in countries: x[c] = {} for q in quarters: x[c][q] = {p: m.Var(lb=0) for p in products}
4. 添加约束条件
约束1:国家×季度的产品线总和=该季度业务单元总预算
for c in countries: for q in quarters: m.Equation(m.sum([x[c][q][p] for p in products]) == quarter_budgets.loc[c, q])
约束2:国家×产品线的全年总和=该国该产品线年度目标
for c in countries: for p in products: m.Equation(m.sum([x[c][q][p] for q in quarters]) == annual_targets.loc[(c, p), 'Target'])
约束3:产品线季度占比符合季节性范围
假设seasonal_constraints表包含各季度的Min_Ratio和Max_Ratio列:
for c in countries: for p in products: annual_p_target = annual_targets.loc[(c, p), 'Target'] if annual_p_target == 0: continue # 目标为0的产品线跳过约束 for q in quarters: min_ratio = seasonal_constraints.loc[p, f'{q}_Min_Ratio'] max_ratio = seasonal_constraints.loc[p, f'{q}_Max_Ratio'] m.Equation(x[c][q][p] >= min_ratio * annual_p_target) m.Equation(x[c][q][p] <= max_ratio * annual_p_target)
约束4:总分配值接近年度总预算(99%精度)
total_allocation = m.sum([x[c][q][p] for c in countries for q in quarters for p in products]) # 允许总分配值在目标值的99%-101%范围内 m.Equation(total_allocation >= 0.99 * total_budget_target) m.Equation(total_allocation <= 1.01 * total_budget_target)
5. 设置目标函数并求解
# 最小化总分配值与目标的绝对偏差 deviation = m.Var(lb=0) m.Equation(total_allocation - total_budget_target <= deviation) m.Equation(total_budget_target - total_allocation <= deviation) m.Obj(deviation) # 执行求解,disp=True显示求解过程 m.solve(disp=True)
6. 结果整理与输出
# 将结果转化为DataFrame result_list = [] for c in countries: for q in quarters: for p in products: result_list.append({ 'Country': c, 'Quarter': q, 'Product': p, 'Allocated_Budget': round(x[c][q][p].value[0], 2) }) result_df = pd.DataFrame(result_list) # 保存到Excel result_df.to_excel('budget_allocation_result.xlsx', index=False)
关键注意事项
- 若模型求解报错,优先检查约束是否冲突(如季节性范围与季度/年度目标矛盾)
- 大规模场景下可调整Gekko参数:
m.options.MAX_ITER = 1000提升迭代上限 - 提前用Pandas清洗数据,处理缺失值(如
df.fillna(0))避免求解异常
内容的提问来源于stack exchange,提问作者JS_DA
相关产品推荐
相关产品推荐

