2024年第十四届MathorCup高校数学建模挑战赛
C题 物流网络分拣中心货量预测及人员排班
原题再现:
电商物流网络在订单履约中由多个环节组成,图1是一个简化的物流网络示意图。其中,分拣中心作为网络的中间环节,需要将包按照不同流向进行分拣并发往下一个场地,最终使包裹到达消费者手中。分拣中心管理效率的提升,对整体网络的履约效率和运作成本起着十分重要的作用。
分拣中心的货量预测是电商物流网络重要的研究问题,对分拣中心货量的精准预测是后续管理及决策的基础,如果管理者可以提前预知之后一段时间各个分拣中心需要操作的货量,便可以提前对资源进行安排。在此场景下的货量预测目标一般有两个:一是根据历史货量、物流网络配信息,预测每个分拣中心每天的货量;二是根据历史货量小时数据,预测每个分拣中心每小时的货量。
分拣中心的货量预测与网络的运输线路有关,通过分析各线路的运输货量,可以得出各分拣中心之间的网络连接关系。当线路关系调整时,可以参考线路的调整信息,得到各分拣中心货量更为准确的预测。
基于分拣中心货量预测的人员排班是接下来要解决的重要问题,分拣中心的人员包含正式工和临时工两种:正式工是场地长期雇佣的人员,工作效率较高;临时工是根据货量情况临时招募的人员,每天可以任意增减,但工作效率相对较低、雇佣成本较高。根据货量预测结果合理安排人员,旨在完成工作的情况下尽可能降低人员成本。针对当前物流网络,其人员安排班次及小时人效指标情况如下:
1)对于所有分拣中心,每天分为6个班次,分别为:00:00-08:00:05:00-13:00,08:00-16:00,12:00-20:00,14:00-22:00,16:00-24:00每个人员(正式工或临时工)每天只能出勤一个班次;
2)小时人效指标为每人每小时完成分拣的包裹量(包裹量即货量),正式工的最高小时人效为 25 包裹/小时,临时工的最高小时人效为 20包裹/小时。
该物流网络包括 57 个分拣中心,每个分拣中心过去4个月的每天货量如附件1所示,过去 30天的每小时货量如附件2所示。基于以上数据,请完成以下问题:
问题 1:建立货量预测模型,对57 个分拣中心未来 30 天每天及每小时的货量进行预测,将预测结果写入结果表1和表2中。
问题 2:过去 90 天各分拣中心之间的各运输线路平均货量如附件3所示。若未来 30 天分拣中心之间的运输线路发生了变化,具体如附件4所示。根据附件 1-4,请对 57 个分拣中心未来 30天每天及每小时的货量进行预测,并将预测结果写入结果表3和表4中。
问题3:假设每个分拣中心有60名正式工,在人员安排时将优先使用正式工,若需额外人员将使用临时工。请基于问题2的预测结果建立模型,给出未来 30 天每个分拣中心每个班次的出勤人数,并写入结果表5中。要求在每天的货量处理完成的基础上,安排的人天数(例如30天每天出勤200 名员工,则总人天数为 6000)尽可能少,且每天的实际小时人效尽量均衡。
问题 4:研究特定分拣中心的排班问题,这里不妨以SC60为例,假设分拣中心 SC60 当前有 200 名正式工,请基于问题2的预测结果建立模型,确定未来 30 天每名正式工及临时工的班次出勤计划,即给出未来 30 天每天六个班次中,每名正式工将在哪些班次出勤,每个班次需要雇佣多少临时工,并写入结果表6中。每名正式工的出勤率(出勤的天数除以总天数30)不能高于 85%,且连续出勤天数不能超过7天。要求在每天货量处理完成的基础上,安排的人天数尽可能少,每天的实际小时人效尽量均衡且正式工出勤率尽量均衡。
整体求解过程概述(摘要)
随着电商物流的发展,网络购物等活动的兴起,分拣中心作为物流运输的关键一环,提高其管理效率对降低运营成本,提高物流行业的运作效率,提升总体竞争力有着至关重要的作用。本文根据不同问题的信息与约束条件,运用一系列方法,得到了较合理的货量预测及人员排班结果。
对于问题一,预测 57个站点未来 30天每天及每小时的货量,我们针对附件 1和附件2的时间序列数据的特点,分别建立了LSTM神经网络模型与ARIMA模型。先对附件1的数据进行了数据预处理,利用LSTM神经网络模型,对每个站点货量进行预测,得到未来30天的货量预测,详见结果表1,。再对附件2的数据进行数据处理,利用ARIMA模型对每个站点货量进行预测,得到未来30天每小时的货量预测,详见结果表2。
对于问题二,在问题 1预测的数据基础上,通过对变化运输路线的分析,将变化路线上的货量按比例向相关分拣中心进行重新分配,获得对应货量变化率,依据货量变化率对分拣中心的货量预测模型进行优化。根据优化后的模型得到各分拣中心未来30天每天和每时的货量预测结果,详见结果表3和结果表4。
对于问题三,基于问题2的预测数据, 根据整数规划对各分拣中心的人员排班最优问题建立数学模型,设立目标为最小化总人天数。建立处理货物量约束、人员优先使用约束、小时人效均衡性约束等约束条件,对目标进行分析,利用简单的任务分配算法对该整数线性规划模型进行求解,得到未来30天各分拣中心每个班次正式工和临时工的出勤人数,详见结果表5。
对于问题四,在问题2 的货量预测基础上,分析特定分拣中心SC60,依据多目标规划对 SC60 的人员排班最优问题建立数学模型,设立两个子目标为最小化总人天数和均衡正式工出勤率。建立处理货物量约束、出勤率约束、连续出勤天数约束等约束条件,对两个子目标进行分析,利用遗传算法得到SC60未来30天的正式工和临时工出勤计划,详见结果表6。
模型假设:
本文将作如下假设,以便于模型的建立与求解:
1、假设所给的历史货物数据均为真实数据。
2、假设货量的变化受历史货量、物流网络配置等内部因素和促销活动、节假日等外部因素的影响。
3、假设对数据中缺失值的处理方式不会对预测结果造成太大的误差。
4、假设历史数据符合时间序列,存在一定的季节性和周期性。
5、假设货量预测与运输线路的变化相关,且这种关系可通过历史数据量化。
6、假设每名正式工和临时工的工作效率在一定范围内波动,但都在最高小时人效标准内。
7、假设每名正式工和临时工每天只能出勤一个班次,且工作时间为8小时。
8、假设每个分拣中心都可以根据需求调整正式工和临时工的人数。
问题分析:
对问题一的分析
将数据按分拣中心进行分组,提取历史数据中的特征,如每日货量、每小时货量、运输线路情况等,同时考虑其他可能影响货量的因素,如节假日、促销活动等,进行数据清洗。由于需要预测的两个量:日货量和时货量有不同的特征,我们使用不同的模型来求解。对于日货量预测,由于其具有时间序列的周期性与依赖性,我们使用LSTM时间序列预测模型,将附件1中过去4个月的每天货量数据和附件2中过去30天的每小时货量数据作为训练数据对模型进行训练,评估检验每个模型的性能,然后利用训练好的模型对每个分拣中心分别预测未来30天的日货量;对于小时货量预测,由于其具有短时间的季节性与周期性,我们使用 ARIMA 模型,再通过选择合适的模型参数分别预测未来30天的时货量。
对问题二的分析
根据附件3和附件4中的数据,考虑过去90天各分拣中心之间的运输线路情况及未来30天分拣中心之间的运输线路的变化,分析线路变化对货量的潜在影响。基于问题一中建立的货量预测模型,对每个分拣中心继续使用时序预测模型。在模型中加入考虑运输线路变化对货量预测的影响,调整模型参数以适应新的线路情况。对于某条线路货量的变化,调整相关分拣中心的货量以反映这一变化。利用新旧路线货量的数据,我们计算出变化率,根据变化率对预测结果进行修正,以此实现对57 个分拣中心未来30天每天货量和每小时货量的预测。
对问题三的分析
设计一个整数线性规划模型,目标函数是最小化总人天数,即所有决策变量的总和。以最大化分拣中心的效率为目的,并满足每个分拣中心的出勤限制。使用历史数据和附件2中的每小时货量数据,以及57个分拣中心的正式工、临时工人数为决策变量,确定目标函数系数,同时考虑每个分拣中心的人员出勤情况、员工效率和工作时间等约束条件。根据历史数据和员工情况,确定每个分拣中心的最佳排班方案。
对问题四的分析
基于问题二的预测结果,计算 SC60 每个班次的货量需求。考虑正式工和临时工的最高小时人效标准,以及出勤率和连续出勤天数的限制条件,建立排班模型。在问题三的基础上,用正式工出勤率方差作为新约束条件,设计优化算法,通过模拟和调整参数,优化排班模型,以确保每天货量都能处理完成,且安排的人天数尽可能少。同时还要确保每天的实际小时人效尽量均衡,正式工出勤率尽量均衡,并满足连续出勤天数和出勤率的限制条件,从而得出未来30天每天六个班次中,每名正式工将在哪些班次出勤,每个班次需要雇佣多少临时工的排班计划。
模型的建立与求解整体论文缩略图
全部论文请见下方" 只会建模 QQ名片" 点击QQ名片即可
部分程序代码:
python
import pandas as pd
import numpy as np
from statsmodels.tsa.statespace.sarimax import SARIMAX
from prophet import Prophet
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from sklearn.preprocessing import MinMaxScaler
# --------------------------
# 数据加载与预处理
# --------------------------
def load_data():
# 假设附件1为daily.csv,附件2为hourly.csv
daily_df = pd.read_csv("附件1-每日货量.csv")
hourly_df = pd.read_csv("附件2-每小时货量.csv")
# 日期格式转换
daily_df['date'] = pd.to_datetime(daily_df['date'])
hourly_df['datetime'] = pd.to_datetime(hourly_df['datetime'])
return daily_df, hourly_df
def preprocess_daily(data):
"""每日数据预处理"""
# 缺失值处理(前向填充)
data = data.fillna(method='ffill')
# 添加时间特征
data['day_of_week'] = data['date'].dt.dayofweek
data['is_holiday'] = data['date'].isin(holiday_dates) # 需定义节假日列表
data['days_to_promotion'] = (data['date'] - pd.to_datetime("2023-11-01")).dt.days
return data
def preprocess_hourly(data):
"""每小时数据预处理"""
# 数据缩放
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(data[['volume']])
# 创建滑动窗口数据集(用过去24小时预测未来24小时)
def create_dataset(data, look_back=24):
X, Y = [], []
for i in range(len(data)-look_back-24):
X.append(data[i:(i+look_back), 0])
Y.append(data[(i+look_back):(i+look_back+24), 0])
return np.array(X), np.array(Y)
X, y = create_dataset(scaled_data)
return X, y, scaler
# --------------------------
# 预测模型
# --------------------------
class DailyForecaster:
"""每日货量预测器"""
def __init__(self):
self.models = {} # 存储每个分拣中心的模型
def train(self, center_id, train_data):
# SARIMA模型训练
model = SARIMAX(train_data,
order=(2,1,2),
seasonal_order=(1,1,1,7),
enforce_stationarity=False)
result = model.fit(disp=False)
self.models[center_id] = result
def predict(self, center_id, steps=30):
model = self.models[center_id]
forecast = model.get_forecast(steps=steps)
return forecast.predicted_mean
class HourlyForecaster:
"""每小时货量预测器"""
def __init__(self):
self.scalers = {}
self.models = {}
def train(self, center_id, X_train, y_train):
# LSTM模型构建
model = Sequential()
model.add(LSTM(64, return_sequences=True, input_shape=(X_train.shape[1], 1)))
model.add(Dropout(0.2))
model.add(LSTM(64))
model.add(Dense(24)) # 预测24小时
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(X_train, y_train, epochs=50, batch_size=32, verbose=0)
self.models[center_id] = model
def predict(self, center_id, last_24h_data, scaler):
model = self.models[center_id]
scaled_input = scaler.transform(last_24h_data.reshape(-1,1))
prediction = model.predict(scaled_input.reshape(1,24,1))
return scaler.inverse_transform(prediction).flatten()
# --------------------------
# 主流程
# --------------------------
if __name__ == "__main__":
# 加载数据
daily_df, hourly_df = load_data()
# 生成每日预测结果表1
daily_forecaster = DailyForecaster()
centers = daily_df['center_id'].unique()
table1 = pd.DataFrame(columns=['date'] + list(centers))
for center in centers:
center_data = daily_df[daily_df['center_id'] == center]
daily_forecaster.train(center, center_data['volume'])
forecast = daily_forecaster.predict(center, 30)
table1[center] = forecast.values
# 生成每小时预测结果表2
hourly_forecaster = HourlyForecaster()
table2 = pd.DataFrame(columns=['date', 'hour'] + list(centers))
for center in centers:
center_hourly = hourly_df[hourly_df['center_id'] == center]
X, y, scaler = preprocess_hourly(center_hourly)
hourly_forecaster.train(center, X, y)
# 获取最后24小时数据作为预测起点
last_24h = center_hourly['volume'].values[-24:]
for day in range(30):
prediction = hourly_forecaster.predict(center, last_24h, scaler)
# 更新最后24小时数据
last_24h = np.append(last_24h[24:], prediction)
# 写入结果
date_range = pd.date_range(start=daily_df['date'].max(), periods=30)
for hour in range(24):
table2.loc[len(table2)] = [
date_range[day].strftime('%Y-%m-%d'),
hour,
prediction[hour]
]
# 结果保存
table1.to_csv("结果表1-每日预测.csv", index=False)
table2.to_csv("结果表2-每小时预测.csv", index=False)