You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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)

(原配图为错误运行结果表格)

问题分析

  1. 目标函数逻辑错误:当前目标是最大化变量的直接求和,忽略了不同列的收益权重差异。实际应该最大化变量与对应原始收益的乘积之和,优先给高收益列分配变量值才能实现总收益最大化。
  2. 约束条件完全错误:当前约束计算的是Max - 变量之和,这和需求中的“总收益不超过Max”完全不匹配,正确约束应为Max - 变量×对应收益之和 ≥ 0。
  3. 优化维度错误:当前把所有行的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 23:32:02