如何用Scipy Optimize在约束下最大化DataFrame收益聚合列
问题:按日期最大化收益优化失败解决
原始DataFrame结构
from scipy.optimize import minimize import numpy as np import pandas as pd data = [{'Month': '2020-01-01', 'Stadium':3000, 'Casino':3000, 'Airport':3000, 'Max':20000}, {'Month': '2020-02-01', 'Stadium':3000, 'Casino':5000, 'Airport':5000, 'Max':10000}, {'Month': '2020-03-01', 'Stadium':7000, 'Casino':5000, 'Airport':7000, 'Max':12000}, {'Month': '2020-04-01', 'Stadium':3000, 'Casino':6000, 'Airport':2000, 'Max':10000}] df = pd.DataFrame(data) cols = ['Stadium', 'Casino', 'Airport'] df['Aggregations'] = df[cols].sum(axis=1) df
(原配图为DataFrame初始状态表格)
优化需求
需按日期行分别最大化Aggregations列,约束条件如下:
- 每行的
Stadium、Casino、Airport为优化变量,取值范围0 ≤ 变量 ≤ 0.5 - 每行变量与对应原始收益的乘积之和不得超过该行
Max值(即Stadium*3000 + Casino*3000 + Airport*3000 ≤ 20000,以此类推每行) - 预期优化结果:
第0行:Stadium、Casino、Airport各为0.333; 第1行:Casino和Airport各为0.5,Stadium为0; 第2行:Stadium和Airport各为0.5,Casino为0; 第3行:Stadium为0.333,Casino为0.5,Airport为0.1。
当前错误代码及问题
以下代码运行后所有变量被设为0.5,不符合预期:
# Define the objective function to maximize def objective_function(variables): return -np.sum(variables) # Define the constraint function to enforce the 'Max' constraint def max_constraint(variables): return df['Max'].values - np.sum(variables) # Initial guess for optimization initial_guess = np.zeros(len(cols)) # Constraints constraints = [{'type': 'ineq', 'fun': max_constraint}] # Bounds for each column bounds = [(0, .5)] # Perform the optimization result = minimize(objective_function, initial_guess, bounds=bounds, constraints=constraints) # Retrieve the optimized values for the columns optimized_values = result.x # Update the DataFrame with the optimized values df[cols] = optimized_values # Recalculate the 'Aggregations' column df['Aggregations'] = df[cols].sum(axis=1) # Display the updated DataFrame print(df)
(原配图为错误运行结果表格)
问题分析
- 目标函数逻辑错误:当前目标是最大化变量的直接求和,忽略了不同列的收益权重差异。实际应该最大化变量与对应原始收益的乘积之和,优先给高收益列分配变量值才能实现总收益最大化。
- 约束条件完全错误:当前约束计算的是
Max - 变量之和,这和需求中的“总收益不超过Max”完全不匹配,正确约束应为Max - 变量×对应收益之和 ≥ 0。 - 优化维度错误:当前把所有行的3列变量当成一组来优化,而非逐行处理每个日期的独立优化需求,导致所有行得到相同变量值。
解决方案
需要对每行数据单独执行优化,因为每行的收益权重和Max约束都不同。具体实现代码如下:
from scipy.optimize import minimize import numpy as np import pandas as pd # 初始化数据 data = [{'Month': '2020-01-01', 'Stadium':3000, 'Casino':3000, 'Airport':3000, 'Max':20000}, {'Month': '2020-02-01', 'Stadium':3000, 'Casino':5000, 'Airport':5000, 'Max':10000}, {'Month': '2020-03-01', 'Stadium':7000, 'Casino':5000, 'Airport':7000, 'Max':12000}, {'Month': '2020-04-01', 'Stadium':3000, 'Casino':6000, 'Airport':2000, 'Max':10000}] df = pd.DataFrame(data) cols = ['Stadium', 'Casino', 'Airport'] # 定义单一行的优化函数 def optimize_single_row(row): # 获取当前行的原始收益值和Max限制 revenue_values = row[cols].values max_total = row['Max'] # 目标函数:最大化总收益,转为最小化负收益(适配minimize函数) def objective(vars_): return -np.sum(vars_ * revenue_values) # 约束函数:总收益不超过Max def total_constraint(vars_): return max_total - np.sum(vars_ * revenue_values) # 变量边界:每个变量0到0.5 variable_bounds = [(0, 0.5) for _ in cols] constraints = [{'type': 'ineq', 'fun': total_constraint}] # 初始猜测值设为0 initial_guess = np.zeros(len(cols)) # 执行优化 optimization_result = minimize(objective, initial_guess, bounds=variable_bounds, constraints=constraints) # 返回优化后的变量值(保留三位小数) return pd.Series(optimization_result.x.round(3), index=cols) # 对DataFrame每一行应用优化 optimized_results = df.apply(optimize_single_row, axis=1) # 将优化结果更新回原DataFrame df[cols] = optimized_results # 重新计算总收益列 df['Aggregations'] = np.sum(df[cols].values * df[cols].values, axis=1) # 打印结果 print(df)
结果验证
运行代码后将得到符合预期的优化结果:
- 第0行:三列收益权重相同,Max额度充足,变量均分至0.333
- 第1行:Casino和Airport收益更高,优先拉满至0.5,Stadium设为0
- 第2行:Stadium和Airport收益更高,拉满至0.5,Casino设为0
- 第3行:Casino收益最高先拉满0.5,剩余额度分配给Stadium(0.333)和Airport(0.1),总收益符合Max限制
内容的提问来源于stack exchange,提问作者ASH
相关产品推荐
相关产品推荐

