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

Python中带启动时间约束的堆叠面积图优化实现求助

解决方案:带启动时间约束的堆叠面积图优化

核心思路

每个项目的人力需求曲线可沿时间轴(X轴)平移,平移量即为项目的启动时间。我们需要在给定约束下,遍历/搜索所有可行的启动时间组合,计算每个组合对应的堆叠曲线目标值(总面积、峰值、斜率平缓度、总曲线长度),最终筛选出Top3最优方案并可视化。

实现步骤与代码

1. 基础准备与约束定义

先明确每个项目的人力曲线、时间轴长度,以及启动时间约束:

  • 时间轴设为0~4(对应原数据的5个时间点)
  • 约束示例:
    • 项目1:1 ≤ x1 < 2(离散时间下取x1=1)
    • 项目2:x2=4(固定启动时间)
    • 项目3:x3=x1(与项目1同步启动)

2. 曲线平移函数

实现函数将项目的人力曲线按启动时间平移,生成对应时间轴上的完整序列:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from itertools import product

def shift_curve(curve, start_time, total_time):
    """
    将项目人力曲线按启动时间平移,生成总时间轴上的序列
    :param curve: 项目原始人力需求列表
    :param start_time: 启动时间(时间轴起始为0)
    :param total_time: 总时间点数量(原数据长度)
    :return: 平移后的人力序列
    """
    shifted = [0]*total_time
    # 曲线从start_time开始填充,超出总时间的部分截断
    end_idx = min(start_time + len(curve), total_time)
    shifted[start_time:end_idx] = curve[:end_idx - start_time]
    return shifted

3. 目标函数定义

根据需求定义四个优化目标:

def calculate_objectives(stacked_curve):
    """计算堆叠曲线的四个目标值"""
    # 1. 总面积:所有时间点人力之和
    total_area = sum(stacked_curve)
    # 2. 峰值:最大人力值
    peak = max(stacked_curve)
    # 3. 斜率平缓度:相邻时间点变化的绝对值之和(越小越平缓)
    slope_smoothness = sum(np.abs(np.diff(stacked_curve)))
    # 4. 总曲线长度:相邻点欧氏距离之和(近似曲线长度)
    curve_length = sum(np.sqrt(np.diff(stacked_curve)**2 + np.ones(len(stacked_curve)-1)**2))
    return {
        'total_area': total_area,
        'peak': peak,
        'slope_smoothness': slope_smoothness,
        'curve_length': curve_length
    }

4. 搜索可行方案并排序

根据约束生成所有可行的启动时间组合,计算每个组合的目标值并排序:

# 原始项目数据
projects = {
    'Project_1': [0,25,36,14,2],
    'Project_2': [2,78,45,11,1],
    'Project_3': [25,16,59,8,0]
}
total_time = len(projects['Project_1'])

# 定义约束下的可行启动时间范围
x1_options = [1]  # 项目1的可行启动时间
x2_options = [4]  # 项目2固定启动时间
x3_options = x1_options  # 项目3与项目1同步

# 生成所有可行组合
valid_combinations = []
for x1, x2, x3 in product(x1_options, x2_options, x3_options):
    # 平移每个项目的曲线
    p1_shifted = shift_curve(projects['Project_1'], x1, total_time)
    p2_shifted = shift_curve(projects['Project_2'], x2, total_time)
    p3_shifted = shift_curve(projects['Project_3'], x3, total_time)
    # 计算堆叠曲线
    stacked = np.array(p1_shifted) + np.array(p2_shifted) + np.array(p3_shifted)
    # 计算目标值
    objs = calculate_objectives(stacked)
    valid_combinations.append({
        'start_times': {'x1':x1, 'x2':x2, 'x3':x3},
        'stacked_curve': stacked,
        'curves': {'Project_1':p1_shifted, 'Project_2':p2_shifted, 'Project_3':p3_shifted},
        **objs
    })

# 按不同目标排序取Top3
sorted_by_area = sorted(valid_combinations, key=lambda x: x['total_area'])[:3]
sorted_by_peak = sorted(valid_combinations, key=lambda x: x['peak'])[:3]
sorted_by_smoothness = sorted(valid_combinations, key=lambda x: x['slope_smoothness'])[:3]

5. 可视化Top3方案

编写函数批量绘制Top3堆叠面积图:

def plot_top_solutions(top_solutions, sort_by):
    fig, axes = plt.subplots(3, 1, figsize=(10, 15))
    for i, sol in enumerate(top_solutions):
        ax = axes[i]
        df = pd.DataFrame(sol['curves'])
        df.plot.area(ax=ax, title=f"Top {i+1} by {sort_by}\n启动时间: {sol['start_times']}")
        ax.set_xlabel('时间')
        ax.set_ylabel('人力资源数量')
        ax.legend(loc='upper right')
        # 添加目标值标注
        ax.text(0.02, 0.95, 
                f"总面积: {sol['total_area']}\n峰值: {sol['peak']}\n平缓度: {sol['slope_smoothness']:.2f}\n曲线长度: {sol['curve_length']:.2f}",
                transform=ax.transAxes, bbox=dict(facecolor='white', alpha=0.8))
    plt.tight_layout()
    plt.show()

# 绘制按总面积排序的Top3
plot_top_solutions(sorted_by_area, '总面积最小')
# 绘制按峰值排序的Top3
plot_top_solutions(sorted_by_peak, '峰值最小')

补充说明

  • 如果约束允许连续时间或更多可选启动时间,可改用scipy.optimize.differential_evolution等优化算法代替枚举,提升搜索效率
  • 可根据业务需求调整目标函数的权重,或组合多个目标进行多目标优化
  • 平移函数可根据实际逻辑调整(比如项目启动后需完整执行曲线,此时总时间轴需延长以容纳完整曲线)

内容的提问来源于stack exchange,提问作者Paul Landrum

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:20:51