基于数据驱动与多目标优化的短途运输货量预测及车辆调度解决方案
2025年MathorCup数学应用挑战赛D题解决方案
问题1:货量预测模型与颗粒度拆解
求解步骤
-
数据预处理
- 提取附件2中各线路历史15天的实际包裹量与附件3的预知数据,分析历史数据与预知数据的误差率。
- 定义生产时段:每天21:00-次日6:00(共54个10分钟间隔)和11:00-14:00(共18个10分钟间隔),总计72个间隔。
-
总货量预测模型
- 考虑预知数据的不完整性,引入历史误差修正因子:
修正因子 = 1 15 ∑ i = 1 15 历史实际货量 i 历史预知货量 i \text{修正因子} = \frac{1}{15} \sum_{i=1}^{15} \frac{\text{历史实际货量}_i}{\text{历史预知货量}_i} 修正因子=151i=1∑15历史预知货量i历史实际货量i - 预测总货量:
Y ^ = 预知货量 × 修正因子 + Δ Y \hat{Y} = \text{预知货量} \times \text{修正因子} + \Delta Y Y^=预知货量×修正因子+ΔY
其中 Δ Y \Delta Y ΔY 为未下单货量与取消订单的补偿量,通过历史数据中“预知货量”与“实际货量”的差值均值估计。
- 考虑预知数据的不完整性,引入历史误差修正因子:
-
10分钟颗粒度拆解
- 根据历史数据计算各时段货量占比,按比例分配总货量至每个10分钟间隔。假设时段占比为
p
t
p_t
pt,则:
y t = Y ^ × p t , ∑ t = 1 72 p t = 1 y_t = \hat{Y} \times p_t, \quad \sum_{t=1}^{72} p_t = 1 yt=Y^×pt,t=1∑72pt=1
- 根据历史数据计算各时段货量占比,按比例分配总货量至每个10分钟间隔。假设时段占比为
p
t
p_t
pt,则:
代码实现(Python)
import pandas as pd
import numpy as np
# 假设附件数据已读取为DataFrame
# 历史数据:df_hist,列:线路编码, 日期, 实际货量, 预知货量
# 未来预知数据:df_future,列:线路编码, 预知货量
# 计算修正因子
def calculate_correction_factor(df_hist, line_code):
hist_data = df_hist[df_hist['线路编码'] == line_code]
return np.mean(hist_data['实际货量'] / hist_data['预知货量'])
# 预测总货量
def predict_total_volume(df_future, line_code, correction_factor):
future_data = df_future[df_future['线路编码'] == line_code]
return future_data['预知货量'].values[0] * correction_factor
# 拆解至10分钟颗粒度(示例:均匀分配至生产时段)
def split_to_10min(volume, start_time, end_time):
# 生产时段总分钟数:9*60+3*60=720分钟,共72个间隔
return [volume / 72] * 72 # 实际需按历史时段占比分配
# 示例:线路“场地3 - 站点83 – 0600”预测
line_code_0600 = "场地3 - 站点83 – 0600"
corr_factor = calculate_correction_factor(df_hist, line_code_0600)
total_volume = predict_total_volume(df_future, line_code_0600, corr_factor)
ten_min_data = split_to_10min(total_volume, "21:00", "14:00")
问题2:运输需求确定与车辆调度
求解步骤
-
确定单车次货量与发运时间
- 单车装载量 C = 1000 C = 1000 C=1000,车次 n = ⌈ Y ^ / C ⌉ n = \lceil \hat{Y}/C \rceil n=⌈Y^/C⌉。
- 发运时间按累计货量达到 C C C 的时间点确定,最晚不超过发运节点(6:00或14:00)。
-
串点方案设计
- 合并剩余货量 < C < C <C 的线路,串点线路数 ≤ 3 \leq 3 ≤3,总货量 ≤ C \leq C ≤C。
- 成本取各线路变动成本的最大值:
串点成本 = max ( 线路1变动成本 , 线路2变动成本 , 线路3变动成本 ) \text{串点成本} = \max(\text{线路1变动成本}, \text{线路2变动成本}, \text{线路3变动成本}) 串点成本=max(线路1变动成本,线路2变动成本,线路3变动成本)
-
自有车辆调度约束
- 时间衔接约束:前任务结束时间
≤
\leq
≤ 后任务发运时间
t 发运前 + 45 分钟(装车) + 2 × t 在途 + 45 分钟(卸车) ≤ t 发运后 t_{\text{发运前}} + 45\text{分钟(装车)} + 2 \times t_{\text{在途}} + 45\text{分钟(卸车)} \leq t_{\text{发运后}} t发运前+45分钟(装车)+2×t在途+45分钟(卸车)≤t发运后 - 目标函数(多目标优化转化为加权和):
min ( α 1 自有车周转率 + β 1 车辆均包裹 + γ 总成本 ) \min \left( \alpha \frac{1}{\text{自有车周转率}} + \beta \frac{1}{\text{车辆均包裹}} + \gamma \text{总成本} \right) min(α自有车周转率1+β车辆均包裹1+γ总成本)
其中 α , β , γ \alpha, \beta, \gamma α,β,γ 为权重系数。
- 时间衔接约束:前任务结束时间
≤
\leq
≤ 后任务发运时间
代码实现(贪心算法)
from datetime import timedelta, datetime
# 自有车辆类
class Vehicle:
def __init__(self, vehicle_id):
self.id = vehicle_id
self.available_time = datetime(2025, 12, 15, 21, 0) # 初始可用时间
# 调度函数
def schedule_vehicles(demands, num_own_vehicles):
own_vehicles = [Vehicle(i) for i in range(num_own_vehicles)]
assignments = []
for demand in sorted(demands, key=lambda x: x['发运时间']):
assigned = False
for vehicle in own_vehicles:
if vehicle.available_time <= demand['发运时间']:
# 计算任务结束时间
end_time = demand['发运时间'] + timedelta(minutes=45) + \
timedelta(hours=2*demand['在途时间']) + timedelta(minutes=45)
assignments.append((demand['线路编码'], demand['发运时间'], f"自有车{vehicle.id}"))
vehicle.available_time = end_time
assigned = True
break
if not assigned:
assignments.append((demand['线路编码'], demand['发运时间'], "外部"))
return assignments
# 示例:线路“场地3 - 站点83 – 0600”调度
demand_0600 = {
'线路编码': "场地3 - 站点83 – 0600",
'发运时间': datetime(2025, 12, 16, 6, 0),
'在途时间': 1.0, # 假设在途时间1小时
}
assignments = schedule_vehicles([demand_0600], num_own_vehicles=5)
问题3:标准容器优化调度
求解步骤
-
调整装载量与时间
- 装载量 C ′ = 800 C' = 800 C′=800,车次 n ′ = ⌈ Y ^ / C ′ ⌉ n' = \lceil \hat{Y}/C' \rceil n′=⌈Y^/C′⌉。
- 装卸载时间缩短为10分钟,时间衔接约束变为:
t 发运前 + 10 分钟(装车) + 2 × t 在途 + 10 分钟(卸车) ≤ t 发运后 t_{\text{发运前}} + 10\text{分钟(装车)} + 2 \times t_{\text{在途}} + 10\text{分钟(卸车)} \leq t_{\text{发运后}} t发运前+10分钟(装车)+2×t在途+10分钟(卸车)≤t发运后
-
决策是否使用容器
- 比较使用容器前后的自有车周转率与成本,选择最优方案:
使用容器条件:自有车周转率提升幅度 > 成本增加幅度 \text{使用容器条件:自有车周转率提升幅度 > 成本增加幅度} 使用容器条件:自有车周转率提升幅度 > 成本增加幅度
- 比较使用容器前后的自有车周转率与成本,选择最优方案:
代码修改
# 修改Vehicle类的时间计算
class ContainerVehicle(Vehicle):
def __init__(self, vehicle_id):
super().__init__(vehicle_id)
self.use_container = False # 是否使用容器
def schedule_with_container(demands, num_own_vehicles):
own_vehicles = [ContainerVehicle(i) for i in range(num_own_vehicles)]
assignments = []
for demand in sorted(demands, key=lambda x: x['发运时间']):
# 优先尝试不使用容器
for vehicle in own_vehicles:
if not vehicle.use_container and vehicle.available_time <= demand['发运时间']:
# 常规时间计算
end_time = demand['发运时间'] + timedelta(minutes=45*2) + timedelta(hours=2*demand['在途时间'])
if end_time <= demand['最晚发运时间']:
assignments.append((..., '是否使用容器': False))
vehicle.available_time = end_time
break
# 若无法分配,尝试使用容器
if not assigned:
for vehicle in own_vehicles:
if vehicle.available_time <= demand['发运时间']:
end_time = demand['发运时间'] + timedelta(minutes=10*2) + timedelta(hours=2*demand['在途时间'])
assignments.append((..., '是否使用容器': True))
vehicle.available_time = end_time
break
return assignments
问题4:预测偏差影响评估
分析框架
-
偏差类型
- 正偏差(预测货量 > 实际货量):导致车次冗余,自有车可能闲置,外部车成本增加。
- 负偏差(预测货量 < 实际货量):导致车次不足,可能延误发运节点,需紧急调度外部车。
-
量化影响
- 偏差率
δ
=
∣
Y
^
−
Y
∣
Y
\delta = \frac{|\hat{Y} - Y|}{Y}
δ=Y∣Y^−Y∣,计算对车次
n
n
n 的影响:
Δ n = ⌈ ( Y ^ ± δ Y ) / C ⌉ − ⌈ Y / C ⌉ \Delta n = \lceil (\hat{Y} \pm \delta Y)/C \rceil - \lceil Y/C \rceil Δn=⌈(Y^±δY)/C⌉−⌈Y/C⌉ - 对总成本的影响: Δ 成本 = Δ n × 外部车成本 \Delta \text{成本} = \Delta n \times \text{外部车成本} Δ成本=Δn×外部车成本(若自有车不足)。
- 偏差率
δ
=
∣
Y
^
−
Y
∣
Y
\delta = \frac{|\hat{Y} - Y|}{Y}
δ=Y∣Y^−Y∣,计算对车次
n
n
n 的影响:
总结
- 问题1通过历史数据修正预知货量,并按时间占比拆解颗粒度。
- 问题2基于贪心算法分配自有车,满足时间约束并优化多目标函数。
- 问题3通过缩短装卸载时间提升自有车周转率,权衡装载量下降的影响。
- 问题4通过偏差率分析对调度结果的定量影响,为鲁棒性优化提供依据。
以上方案结合时间序列分析、整数规划与启发式算法,实现从货量预测到车辆调度的全流程优化,平衡效率与成本目标。