2024年 Mathorcup高校数学建模竞赛(C题)| 物流网络分拣中心 | 线性规划,流网络,多目标规划联合,小鹿学长带队指引全代码文章与思路
我是鹿鹿学长,就读于上海交通大学,截至目前已经帮200+人完成了建模与思路的构建的处理了~本篇文章是鹿鹿学长经过深度思考,独辟蹊径,通过多目标规划解决物流网络分拣中心问题。结合线性规划,流网络等多元算法,实现综合建模。独创复杂系统视角,帮助你解决mathorcup的难关呀。完整内容可以在文章末尾领取!该段文字的第一个问题是建立货量预测模型,对57个分拣中心未来30天每天及每小时的货量进行预测。假设
我是鹿鹿学长,就读于上海交通大学,截至目前已经帮200+人完成了建模与思路的构建的处理了~
本篇文章是鹿鹿学长经过深度思考,独辟蹊径,通过多目标规划解决物流网络分拣中心问题。结合线性规划,流网络等多元算法,实现综合建模。独创复杂系统视角,帮助你解决mathorcup的难关呀。
完整内容可以在文章末尾领取!
该段文字的第一个问题是建立货量预测模型,对57个分拣中心未来30天每天及每小时的货量进行预测。
假设每个分拣中心的每天货量为 x i x_i xi,其中 i = 1 , 2 , . . . , 57 i=1,2,...,57 i=1,2,...,57,每个分拣中心的每小时货量为 y i j y_{ij} yij,其中 j = 1 , 2 , . . . , 720 j=1,2,...,720 j=1,2,...,720,则问题可以建模为:
-
每天货量预测问题:
x i ^ = α x i − 1 + β x i − 2 + γ x i − 3 + δ x i − 4 \hat{x_i}=\alpha x_{i-1} + \beta x_{i-2} + \gamma x_{i-3} + \delta x_{i-4} xi^=αxi−1+βxi−2+γxi−3+δxi−4
其中, α , β , γ , δ \alpha,\beta,\gamma,\delta α,β,γ,δ为待估参数,代表过去四天的货量对当天货量的影响程度。该模型基于过去四天的数据进行预测,可以反映近期的变化趋势。 -
每小时货量预测问题:
y i j ^ = α y i ( j − 1 ) + β y i ( j − 2 ) + γ y i ( j − 3 ) + δ y i ( j − 4 ) \hat{y_{ij}}=\alpha y_{i(j-1)} + \beta y_{i(j-2)} + \gamma y_{i(j-3)} + \delta y_{i(j-4)} yij^=αyi(j−1)+βyi(j−2)+γyi(j−3)+δyi(j−4)
其中, α , β , γ , δ \alpha,\beta,\gamma,\delta α,β,γ,δ为待估参数,代表过去四小时的货量对当小时货量的影响程度。该模型基于过去四小时的数据进行预测,可以反映当天的变化趋势。
以上模型可以使用最小二乘法进行参数估计,得到预测结果。
另外,还可以结合附件3和附件4中的运输线路信息,利用线性回归模型建立分拣中心之间的货量预测模型,即:
x
i
^
=
α
1
x
i
−
1
+
α
2
x
i
−
2
+
.
.
.
+
α
57
x
i
−
57
+
β
i
1
x
i
−
1
+
β
i
2
x
i
−
2
+
.
.
.
+
β
i
57
x
i
−
57
\hat{x_i}=\alpha_1x_{i-1} + \alpha_2x_{i-2} + ... + \alpha_{57}x_{i-57} + \beta_{i1}x_{i-1} + \beta_{i2}x_{i-2} + ... + \beta_{i57}x_{i-57}
xi^=α1xi−1+α2xi−2+...+α57xi−57+βi1xi−1+βi2xi−2+...+βi57xi−57
其中,
α
i
\alpha_i
αi代表分拣中心
i
i
i的历史货量对自身货量的影响程度,
β
i
j
\beta_{ij}
βij代表分拣中心
j
j
j的历史货量对分拣中心
i
i
i货量的影响程度。该模型可以反映不同分拣中心之间的相互影响关系,从而提高预测精度。
综上所述,针对第一个问题,可以建立基于过去货量数据的预测模型,也可以结合运输线路信息建立分拣中心之间的货量预测模型。最终的预测结果可以使用最小二乘法进行参数估计得到。
根据问题描述,我们可以将货量预测问题归纳为时间序列预测问题。即根据过去的数据来预测未来一段时间内的货量情况。对于时间序列预测问题,常用的方法有ARIMA模型、指数平滑模型等。在这里,我们采用指数平滑模型来建立货量预测模型。
首先,我们将每个分拣中心的货量数据按照日期进行分组,然后对每个分组的数据进行指数平滑处理。指数平滑是一种常用的时间序列预测方法,它通过对历史数据的加权平均来预测未来的值。具体来说,指数平滑模型的预测公式为:
y ^ t + 1 = α y t + ( 1 − α ) y ^ t \hat{y}_{t+1} = \alpha y_t + (1-\alpha)\hat{y}_t y^t+1=αyt+(1−α)y^t
其中, y ^ t + 1 \hat{y}_{t+1} y^t+1是下一个时间点的预测值, y t y_t yt是当前时间点的实际值, y ^ t \hat{y}_t y^t是上一个时间点的预测值, α \alpha α是平滑参数,通常取值范围为0到1之间。
根据问题描述,每个分拣中心的货量数据可能受到运输线路、季节性等因素的影响。因此,我们可以对不同的分组数据使用不同的平滑参数。比如,对于过去30天的每小时货量数据,我们可以选择 α \alpha α=0.5,对于过去4个月的每天货量数据,我们可以选择 α \alpha α=0.3。通过不断调整平滑参数,我们可以得到最佳的预测结果。
另外,为了更加准确地预测未来的货量,我们还可以考虑使用加权指数平滑模型。加权指数平滑模型会对历史数据的加权平均进行平滑处理,从而减少预测误差。具体来说,加权指数平滑模型的预测公式为:
y ^ t + 1 = ∑ i = 1 n ω i y t − i + 1 \hat{y}_{t+1} = \sum_{i=1}^{n}\omega_i y_{t-i+1} y^t+1=i=1∑nωiyt−i+1
其中, y ^ t + 1 \hat{y}_{t+1} y^t+1是下一个时间点的预测值, y t − i + 1 y_{t-i+1} yt−i+1是过去n个时间点的实际值, ω i \omega_i ωi是权重系数,满足 ∑ i = 1 n ω i = 1 \sum_{i=1}^{n}\omega_i = 1 ∑i=1nωi=1。
最后,我们可以将预测结果写入结果表1和2中,供管理者参考。同时,为了提高预测的准确性,我们还可以对模型进行不断的优化和调整,比如使用其他的时间序列预测方法、引入其他的影响因素等。
问题1:建立货量预测模型,对57个分拣中心未来30天每天及每小时的货量进行预测。
假设分拣中心的货量预测模型为线性回归模型,假设每个分拣中心的货量受到历史货量、物流网络配置以及其他因素的影响,可以表示为:
y = β 0 + β 1 x 1 + β 2 x 2 + ⋯ + β n x n y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \cdots + \beta_n x_n y=β0+β1x1+β2x2+⋯+βnxn
其中, y y y表示未来货量, β 0 \beta_0 β0表示截距项, β 1 , β 2 , ⋯ , β n \beta_1, \beta_2, \cdots, \beta_n β1,β2,⋯,βn表示各个影响因素的系数, x 1 , x 2 , ⋯ , x n x_1, x_2, \cdots, x_n x1,x2,⋯,xn表示各个影响因素的值。
根据问题描述,影响货量的因素包括历史货量、物流网络配置等信息,因此可以将模型改写为:
y = β 0 + β 1 x 1 + β 2 x 2 + ⋯ + β n x n + ε y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \cdots + \beta_n x_n + \varepsilon y=β0+β1x1+β2x2+⋯+βnxn+ε
其中, ε \varepsilon ε为误差项。
为了预测未来30天每天和每小时的货量,需要获取历史货量数据和物流网络配置信息。然后使用这些数据来训练模型,得到各个影响因素的系数,从而可以预测未来的货量。
具体步骤如下:
-
收集历史货量数据和物流网络配置信息。历史货量数据可以通过附件1和附件2中的数据获得,物流网络配置信息可以通过附件3中的数据获得。
-
对数据进行预处理。例如,对日期进行转换,将日期转换为星期几或者工作日/非工作日等信息。对物流网络配置信息进行编码,例如使用独热编码等方式。
-
将数据分为训练集和测试集。训练集可以使用过去的历史数据,测试集可以使用最近的数据。
-
使用训练集来训练模型。可以使用最小二乘法等方法来估计各个影响因素的系数。
-
使用测试集来评估模型的性能。可以使用均方根误差等指标来评估模型的表现。
-
使用训练好的模型来预测未来的货量。可以使用附件4中的物流网络配置信息来调整模型,从而预测出更精确的结果。
-
将预测结果写入结果表1和表2中。
# 导入所需的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# 读取附件1和附件2数据
df_daily = pd.read_excel('附件1.xlsx')
df_hourly = pd.read_excel('附件2.xlsx')
# 处理附件1数据,取出分拣中心名称和每天货量数据
df_daily = df_daily[['分拣中心名称', '货量']]
# 处理附件2数据,取出分拣中心名称和每小时货量数据
df_hourly = df_hourly[['分拣中心名称', '时间', '货量']]
# 将每小时数据按分拣中心名称和日期进行分组,计算每天的总货量
df_hourly_daily = df_hourly.groupby(['分拣中心名称', '时间'])['货量'].sum().reset_index()
# 将每天的总货量数据合并到附件1数据中
df_daily = pd.merge(df_daily, df_hourly_daily, on='分拣中心名称')
# 对每天货量数据进行线性回归拟合,得到每天的预测货量
# 将数据按分拣中心名称进行分组,对每组数据进行线性回归拟合
# 将每组数据的预测结果合并到最终的结果表1中
result1 = pd.DataFrame(columns=['分拣中心名称', '预测货量'])
for name, group in df_daily.groupby('分拣中心名称'):
x = group.index.values.reshape(-1, 1)
y = group['货量'].values.reshape(-1, 1)
reg = LinearRegression().fit(x, y)
y_pred = reg.predict(np.arange(1, 31).reshape(-1, 1))
result1 = result1.append(pd.DataFrame({'分拣中心名称': name, '预测货量': y_pred.flatten()}))
# 对每小时货量数据进行线性回归拟合,得到每小时的预测货量
# 将数据按分拣中心名称和时间进行分组,对每组数据进行线性回归拟合
# 将每组数据的预测结果合并到最终的结果表2中
result2 = pd.DataFrame(columns=['分拣中心名称', '时间', '预测货量'])
for name, group in df_hourly.groupby(['分拣中心名称', '时间']):
x = group.index.values.reshape(-1, 1)
y = group['货量'].values.reshape(-1, 1)
reg = LinearRegression().fit(x, y)
y_pred = reg.predict(np.arange(1, 721).reshape(-1, 1))
result2 = result2.append(pd.DataFrame({'分拣中心名称': name[0], '时间': name[1], '预测货量': y_pred.flatten()}))
# 将结果写入Excel表格中
with pd.ExcelWriter('结果表1.xlsx') as writer:
result1.to_excel(writer, sheet_name='每天预测货量', index=False)
with pd.ExcelWriter('结果表2.xlsx') as writer:
result2.to_excel(writer, sheet_name='每小时预测货量', index=False)
第二个问题是根据过去90天各分拣中心之间的运输线路平均货量以及未来30天分拣中心之间运输线路发生变化情况,预测57个分拣中心未来30天每天及每小时的货量,并将预测结果写入结果表3和表4中。
首先,我们可以将每个分拣中心看作是一个节点,各线路之间的运输货量可以看作是各节点之间的连接关系。根据过去90天各分拣中心之间的运输线路平均货量以及未来30天分拣中心之间运输线路发生变化情况,我们可以得到一个相邻矩阵 A = [ a i j ] A=[a_{ij}] A=[aij],其中 a i j a_{ij} aij表示分拣中心 i i i和 j j j之间的运输货量,如果 i i i和 j j j之间没有运输线路,则 a i j = 0 a_{ij}=0 aij=0。根据矩阵 A A A,我们可以得到每个分拣中心的入度(即进入该分拣中心的货量总和)和出度(即从该分拣中心出去的货量总和)。
假设每个分拣中心的货量预测结果为 y i ( t ) y_i(t) yi(t),其中 t t t表示时间, i = 1 , 2 , . . . , 57 i=1,2,...,57 i=1,2,...,57。根据题目所给的信息,我们可以得到以下条件:
-
每个分拣中心每天分为6个班次,每个人员每天只能出勤一个班次,即每天最多只能出勤6个班次。
-
正式工的最高小时人效为25包裹/小时,临时工的最高小时人效为20包裹/小时。
-
分拣中心的人员包括正式工和临时工,每天可以任意增减。
-
假设每个分拣中心有 N i N_i Ni名正式工, M i M_i Mi名临时工,其中 i = 1 , 2 , . . . , 57 i=1,2,...,57 i=1,2,...,57。
根据以上条件,我们可以得到以下模型:
- 每个分拣中心每天的货量预测结果 y i ( t ) y_i(t) yi(t)应该满足以下条件:
y i ( t ) ≤ N i × 25 + M i × 20 y_i(t) \leq N_i \times 25 + M_i \times 20 yi(t)≤Ni×25+Mi×20
即每天的总货量不应该超过正式工和临时工的最大工作效率。
- 每个分拣中心每天的货量预测结果应该满足以下条件:
y i ( t ) ≥ N i × 25 + M i × 20 − ∑ j = 1 57 a j i y j ( t ) y_i(t) \geq N_i \times 25 + M_i \times 20 - \sum_{j=1}^{57}a_{ji}y_j(t) yi(t)≥Ni×25+Mi×20−j=1∑57ajiyj(t)
即每天的总货量应该大于等于进入该分拣中心的货量减去从其他分拣中心出去的货量。
- 每个分拣中心每天的货量预测结果应该满足以下条件:
y i ( t ) ≥ 0 y_i(t) \geq 0 yi(t)≥0
即每天的货量应该大于等于0。
- 每个分拣中心每天的货量预测结果应该满足以下条件:
y i ( t ) = y i ( t − 1 ) + ∑ j = 1 57 a i j y j ( t − 1 ) y_i(t) = y_i(t-1) + \sum_{j=1}^{57}a_{ij}y_j(t-1) yi(t)=yi(t−1)+j=1∑57aijyj(t−1)
即每天的货量预测结果应该等于前一天的货量加上从其他分拣中心进入该分拣中心的货量。
- 每个分拣中心每天的货量预测结果应该满足以下条件:
N i ≥ 0 , M i ≥ 0 N_i \geq 0, M_i \geq 0 Ni≥0,Mi≥0
即正式工和临时工的数量应该大于等于0。
根据以上条件,我们可以建立一个线性规划模型:
min ∑ i = 1 57 ∑ t = 1 30 ( N i + M i ) s.t. y i ( t ) ≤ N i × 25 + M i × 20 , ∀ i = 1 , 2 , . . . , 57 , t = 1 , 2 , . . . , 30 y i ( t ) ≥ N i × 25 + M i × 20 − ∑ j = 1 57 a j i y j ( t ) , ∀ i = 1 , 2 , . . . , 57 , t = 1 , 2 , . . . , 30 y i ( t ) ≥ 0 , ∀ i = 1 , 2 , . . . , 57 , t = 1 , 2 , . . . , 30 y i ( t ) = y i ( t − 1 ) + ∑ j = 1 57 a i j y j ( t − 1 ) , ∀ i = 1 , 2 , . . . , 57 , t = 2 , 3 , . . . , 30 N i ≥ 0 , M i ≥ 0 , ∀ i = 1 , 2 , . . . , 57 y i ( 1 ) = y i ( 0 ) = 0 , ∀ i = 1 , 2 , . . . , 57 \begin{aligned} \min & \sum_{i=1}^{57} \sum_{t=1}^{30} (N_i + M_i) \\ \text{s.t.} & y_i(t) \leq N_i \times 25 + M_i \times 20, \forall i=1,2,...,57, t=1,2,...,30 \\ & y_i(t) \geq N_i \times 25 + M_i \times 20 - \sum_{j=1}^{57}a_{ji}y_j(t), \forall i=1,2,...,57, t=1,2,...,30 \\ & y_i(t) \geq 0, \forall i=1,2,...,57, t=1,2,...,30 \\ & y_i(t) = y_i(t-1) + \sum_{j=1}^{57}a_{ij}y_j(t-1), \forall i=1,2,...,57, t=2,3,...,30 \\ & N_i \geq 0, M_i \geq 0, \forall i=1,2,...,57 \\ & y_i(1) = y_i(0) = 0, \forall i=1,2,...,57 \\ \end{aligned} mins.t.i=1∑57t=1∑30(Ni+Mi)yi(t)≤Ni×25+Mi×20,∀i=1,2,...,57,t=1,2,...,30yi(t)≥Ni×25+Mi×20−j=1∑57ajiyj(t),∀i=1,2,...,57,t=1,2,...,30yi(t)≥0,∀i=1,2,...,57,t=1,2,...,30yi(t)=yi(t−1)+j=1∑57aijyj(t−1),∀i=1,2,...,57,t=2,3,...,30Ni≥0,Mi≥0,∀i=1,2,...,57yi(1)=yi(0)=0,∀i=1,2,...,57
其中, y i ( t ) y_i(t) yi(t)表示分拣中心 i i i在第 t t t天的货量预测结果, N i N_i Ni和 M i M_i Mi分别表示分拣中心 i i i的正式工和临时工的数量。
通过求解以上线性规划模型,我们可以得到每个分拣中心未来30天每天的货量预测结果,即结果表3中的数据。根据每天的货量预测结果,我们可以进一步得到每个分拣中心未来30天每小时的货量预测结果,即结果表4中的数据。
问题2:假设某个分拣中心i在未来第t天的货量为 y i t y_{it} yit,则可以基于过去90天该分拣中心与其他分拣中心的运输线路平均货量 y i j y_{ij} yij,以及未来30天该分拣中心与其他分拣中心的运输线路变化情况 Δ y i j \Delta y_{ij} Δyij,建立如下模型:
y i t = ∑ j = 1 57 y i j + ∑ j = 1 57 Δ y i j y_{it} = \sum_{j=1}^{57} y_{ij} + \sum_{j=1}^{57} \Delta y_{ij} yit=j=1∑57yij+j=1∑57Δyij
其中, y i t y_{it} yit的含义为未来第t天该分拣中心的货量, y i j y_{ij} yij的含义为过去90天该分拣中心与其他分拣中心的平均运输货量, Δ y i j \Delta y_{ij} Δyij的含义为未来30天该分拣中心与其他分拣中心运输线路变化的影响。该模型基于过去90天的平均货量和未来30天的变化情况,可以较为准确地预测出每个分拣中心未来30天每天的货量情况。
对于每小时的货量预测,可以根据过去30天的每小时货量数据,建立类似的模型:
y i t h = ∑ j = 1 57 y i j h + ∑ j = 1 57 Δ y i j h y_{ith} = \sum_{j=1}^{57} y_{ijh} + \sum_{j=1}^{57} \Delta y_{ijh} yith=j=1∑57yijh+j=1∑57Δyijh
其中, y i t h y_{ith} yith的含义为未来第t天第h小时该分拣中心的货量, y i j h y_{ijh} yijh的含义为过去30天该分拣中心与其他分拣中心的平均运输货量, Δ y i j h \Delta y_{ijh} Δyijh的含义为未来30天该分拣中心与其他分拣中心运输线路变化的影响。
该模型可以根据过去30天的小时级数据和未来30天的运输线路变化情况,较为准确地预测出每个分拣中心未来30天每小时的货量情况。同时,该模型也可以根据运输线路变化情况,对分拣中心之间的货量分配进行调整,从而提高整个物流网络的运作效率。
总的来说,该模型综合考虑了过去90天的平均货量和未来30天的运输线路变化情况,可以较为准确地预测出每个分拣中心未来30天每天及每小时的货量情况。同时,该模型也可以根据运输线路变化情况,对分拣中心之间的货量分配进行调整,从而提高整个物流网络的运作效率。
问题2:建立分拣中心货量预测模型
首先,根据过去90天各分拣中心之间的运输线路平均货量,可以得出各分拣中心之间的网络连接关系。假设共有N个分拣中心,那么可以用一个N*N的矩阵表示各分拣中心之间的运输线路平均货量,记为 A = [ a i j ] N × N A=[a_{ij}]_{N\times N} A=[aij]N×N,其中 a i j a_{ij} aij 表示从第i个分拣中心到第j个分拣中心的运输线路平均货量。
接下来,根据附件4中未来30天分拣中心之间运输线路发生变化情况,可以得到一个N*N的矩阵,记为 B = [ b i j ] N × N B=[b_{ij}]_{N\times N} B=[bij]N×N,其中 b i j b_{ij} bij 表示从第i个分拣中心到第j个分拣中心的运输线路变化情况。若运输线路发生变化,则 b i j b_{ij} bij 的值为1,否则为0。
然后,根据附件1和附件2中的数据,可以得到每个分拣中心过去4个月的每天货量和过去30天的每小时货量。记第i个分拣中心过去4个月每天的货量为 C i = [ c i 1 , c i 2 , ⋯ , c i 120 ] C_i=[c_{i1},c_{i2},\cdots,c_{i120}] Ci=[ci1,ci2,⋯,ci120],其中 c i j c_{ij} cij 表示第i个分拣中心过去第j天的货量;记第i个分拣中心过去30天每小时的货量为 D i = [ d i 1 , d i 2 , ⋯ , d i 720 ] D_i=[d_{i1},d_{i2},\cdots,d_{i720}] Di=[di1,di2,⋯,di720],其中 d i j d_{ij} dij 表示第i个分拣中心过去第j小时的货量。
基于以上数据,可以建立货量预测模型,预测每个分拣中心未来30天每天及每小时的货量。假设所建立的模型为 f ( C 1 , C 2 , ⋯ , C N , D 1 , D 2 , ⋯ , D N , A , B ) f(C_1,C_2,\cdots,C_N,D_1,D_2,\cdots,D_N,A,B) f(C1,C2,⋯,CN,D1,D2,⋯,DN,A,B),其中 f f f 是一个函数,其输入为每个分拣中心过去的货量数据和网络连接关系数据,输出为每个分拣中心未来30天每天及每小时的货量预测结果。具体可表示为:
每天货量预测结果:
F
d
a
i
l
y
=
[
f
(
C
1
,
C
2
,
⋯
,
C
N
,
A
,
B
)
]
N
×
30
\begin{equation} F_{daily}=[f(C_1,C_2,\cdots,C_N,A,B)]_{N\times 30} \end{equation}
Fdaily=[f(C1,C2,⋯,CN,A,B)]N×30
每小时货量预测结果:
F
h
o
u
r
l
y
=
[
f
(
D
1
,
D
2
,
⋯
,
D
N
,
A
,
B
)
]
N
×
720
\begin{equation} F_{hourly}=[f(D_1,D_2,\cdots,D_N,A,B)]_{N\times 720} \end{equation}
Fhourly=[f(D1,D2,⋯,DN,A,B)]N×720
将预测结果写入结果表3和表4中即可。
附件3:过去90天各分拣中心之间的运输线路平均货量数据,共90天,按时间顺序排列,共N*N个数据,其中第i个数据表示第i个分拣中心过去90天每天的运输线路平均货量。
附件4:未来30天分拣中心之间运输线路发生变化情况,共N*N个数据,其中第i个数据为1表示第i个分拣中心的运输线路发生了变化,为0表示未发生变化。
# 导入必要的库
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
# 读取数据
historical_data = pd.read_excel('附件1:各分拣中心过去4个月每天货量.xlsx', index_col=0)
hourly_data = pd.read_excel('附件2:过去30天每小时货量.xlsx', index_col=0)
average_route_data = pd.read_excel('附件3:过去90天各分拣中心之间的运输线路平均货量.xlsx', index_col=0)
new_route_data = pd.read_excel('附件4:未来30天分拣中心之间运输线路发生变化情况.xlsx', index_col=0)
# 数据清洗和处理
historical_data = historical_data.T # 转置数据,使每一列代表一个分拣中心
average_route_data = average_route_data.fillna(0) # 填充缺失值
new_route_data = new_route_data.fillna(0) # 填充缺失值
# 建立货量预测模型
# 对每天货量进行预测
# 创建结果表1
result_table1 = pd.DataFrame(index=historical_data.index, columns=historical_data.columns)
for center in historical_data.columns:
# 提取历史数据
X = historical_data.index.to_numpy().reshape(-1, 1)
y = historical_data[center].to_numpy().reshape(-1, 1)
# 训练线性回归模型
model = LinearRegression()
model.fit(X, y)
# 预测未来30天每天的货量
future_X = np.arange(1, 31).reshape(-1, 1)
result = model.predict(future_X)
# 将预测结果写入结果表1
result_table1[center] = result
# 对每小时货量进行预测
# 创建结果表2
result_table2 = pd.DataFrame(index=hourly_data.index, columns=hourly_data.columns)
for center in hourly_data.columns:
# 提取历史数据
X = hourly_data.index.to_numpy().reshape(-1, 1)
y = hourly_data[center].to_numpy().reshape(-1, 1)
# 训练线性回归模型
model = LinearRegression()
model.fit(X, y)
# 预测未来30天每小时的货量
future_X = np.arange(1, 721).reshape(-1, 1)
result = model.predict(future_X)
# 将预测结果写入结果表2
result_table2[center] = result
# 过去90天各分拣中心之间的运输线路平均货量
# 根据过去90天各分拣中心之间的运输线路平均货量以及未来30天分拣中心之间运输线路发生变化情况,预测未来30天每天及每小时的货量
# 创建结果表3和表4
result_table3 = pd.DataFrame(index=historical_data.index, columns=historical_data.columns)
result_table4 = pd.DataFrame(index=hourly_data.index, columns=hourly_data.columns)
for center in historical_data.columns:
# 提取历史数据
X = average_route_data.index.to_numpy().reshape(-1, 1)
y = average_route_data[center].to_numpy().reshape(-1, 1)
# 训练线性回归模型
model = LinearRegression()
model.fit(X, y)
# 预测未来30天每天的货量
future_X = np.arange(1, 31).reshape(-1, 1)
result = model.predict(future_X)
# 将预测结果写入结果表3
result_table3[center] = result
# 预测未来30天每小时的货量
future_X = np.arange(1, 721).reshape(-1, 1)
result = model.predict(future_X)
# 将预测结果写入结果表4
result_table4[center] = result
# 人员安排
# 创建结果表5
result_table5 = pd.DataFrame(index=historical_data.columns, columns=['00:00-08:00', '05:00-13:00', '08:00-16:00', '12:00-20:00', '14:00-22:00', '16:00-24:00'])
# 对每个班次进行人员安排
for shift in result_table5.columns:
# 创建临时表,用于存放每个分拣中心每天的货量
temp = pd.DataFrame(index=historical_data.index, columns=historical_data.columns)
# 填充临时表
for center in historical_data.columns:
if shift == '00:00-08:00':
temp[center] = result_table3[center] * 6 # 每天分为六个班次,每个班次时长为8小时,因此每天的货量为预测结果乘以6
elif shift == '05:00-13:00':
temp[center] = result_table3[center] * 8
elif shift == '08:00-16:00':
temp[center] = result_table3[center] * 8
elif shift == '12:00-20:00':
temp[center] = result_table3[center] * 8
elif shift == '14:00-22:00':
temp[center] = result_table3[center] * 8
elif shift == '16:00-24:00':
temp[center] = result_table3[center] * 8
# 对临时表进行排序,得到每个班次每个分拣中心的货量
temp = temp.sort_values(by=shift, ascending=False)
# 将临时表的前60个分拣中心填入结果表5
result_table5[shift] = temp.iloc[:60].index.to_list()
# 输出结果表5
print(result_table5)
# 排班问题
# 选择特定分拣中心SC60作为例子
# 创建结果表6
result_table6 = pd.DataFrame(index=historical_data.index, columns=['00:00-08:00', '05:00-13:00', '08:00-16:00', '12:00-20:00', '14:00-22:00', '16:00-24:00'])
# 提取特定分拣中心SC60的数据
X = hourly_data.index.to_numpy().reshape(-1, 1)
y = hourly_data['SC60'].to_numpy().reshape(-1, 1)
# 训练线性回归模型
model = LinearRegression()
model.fit(X, y)
# 预测未来30天每小时的货量
future_X = np.arange(1, 721).reshape(-1, 1)
result = model.predict(future_X)
# 将预测结果写入结果表6
result_table6['SC60'] = result
# 对结果表6进行处理,得到每名正式工及临时工的班次出勤计划
for shift in result_table6.columns:
# 将每名正式工的出勤率设为0
attendance_rate = 0
# 循环直到每名正式工的出勤率达到85%
while attendance_rate < 0.85:
# 创建临时表,用于存放每个班次每名正式工及其雇佣的临时工数
temp = pd.DataFrame(index=result_table6.index, columns=['regular_staff', 'temporary_staff'])
# 将每名正式工的出勤率设为0
attendance_rate = 0
# 填充临时表
for index, row in result_table6.iterrows():
# 初始化每名正式工的出勤天数为0
days_attended = 0
# 初始化每个班次需要雇佣的临时工数为0
temp.loc[index, 'temporary_staff'] = 0
for column in result_table6.columns:
# 如果当前班次的货量大于0,则认为该正式工在该班次出勤
if row[column] > 0:
days_attended += 1
temp.loc[index, 'temporary_staff'] += result_table6.loc[index, column] / 20 # 每个临时工每小时的货量为20包裹,因此需要雇佣的临时工数为预测结果除以20
# 如果该正式工的出勤天数大于0,则计算出勤率
if days_attended > 0:
attendance_rate = days_attended / 30
# 将每名正式工的出勤天数填入临时表
temp.loc[index, 'regular_staff'] = days_attended
# 将临时表按照每名正式工的出勤天数进行排序
temp = temp.sort_values(by='regular_staff', ascending=False)
# 将临时表的前200名正式工填入结果表6
result_table6[shift] = temp.iloc[:200].index.to_list()
# 输出结果表6
print(result_table6)
问题3:基于问题2的预测结果,建立分拣中心人员排班模型,确定未来30天每个分拣中心每个班次的出勤人数,并尽可能降低总人天数,平衡每天的实际小时人效。
首先,定义变量:
x
i
,
j
x_{i,j}
xi,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的正式工人数;
y
i
,
j
y_{i,j}
yi,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的临时工人数;
w
i
w_i
wi 表示第
i
i
i 个分拣中心的总员工数;
c
i
,
j
c_{i,j}
ci,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的总人天数;
d
i
,
j
d_{i,j}
di,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的小时人效指标;
a
i
,
j
a_{i,j}
ai,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的实际小时人效;
b
i
,
j
b_{i,j}
bi,j 表示第
i
i
i 个分拣中心在第
j
j
j 个班次的出勤率。
目标函数:
最小化总人天数,即
m
i
n
∑
i
=
1
57
∑
j
=
1
6
c
i
,
j
min \sum_{i=1}^{57}\sum_{j=1}^{6}c_{i,j}
min∑i=157∑j=16ci,j
约束条件:
- 每个分拣中心每个班次的出勤人数不能超过总员工数,即 x i , j + y i , j ≤ w i , ∀ i , j x_{i,j} + y_{i,j} \leq w_i, \forall i,j xi,j+yi,j≤wi,∀i,j
- 每个分拣中心每天只能出勤一个班次,即 ∑ j = 1 6 x i , j + ∑ j = 1 6 y i , j ≤ 1 , ∀ i \sum_{j=1}^{6}x_{i,j} + \sum_{j=1}^{6}y_{i,j} \leq 1, \forall i ∑j=16xi,j+∑j=16yi,j≤1,∀i
- 每个班次的总人天数不能超过8小时,即 c i , j ≤ 8 , ∀ i , j c_{i,j} \leq 8, \forall i,j ci,j≤8,∀i,j
- 每个班次的实际小时人效不能超过小时人效指标,即 a i , j ≤ d i , j , ∀ i , j a_{i,j} \leq d_{i,j}, \forall i,j ai,j≤di,j,∀i,j
- 每个班次的出勤率不能超过85%,即 b i , j ≤ 0.85 , ∀ i , j b_{i,j} \leq 0.85, \forall i,j bi,j≤0.85,∀i,j
- 连续出勤天数不能超过7天,即 ∑ j = 1 6 b i , j ≤ 7 , ∀ i \sum_{j=1}^{6}b_{i,j} \leq 7, \forall i ∑j=16bi,j≤7,∀i
求解上述优化问题,得到每个分拣中心每个班次的出勤人数,即为所求结果。
问题3的目标是在满足每天的货量处理需求的基础上,尽可能降低总的人天数,并平衡每天的实际小时人效。为了实现这个目标,首先需要确定每个分拣中心每个班次的出勤人数,在保证满足每天的货量处理需求的前提下,尽可能使用正式工,从而降低临时工的雇佣成本。
为了达到这个目标,可以建立如下的数学模型:
假设每个分拣中心 i i i需要在第 t t t天的第 k k k个班次(例如,第1个班次为00:00-08:00)安排 x i , t , k x_{i,t,k} xi,t,k名正式工和 y i , t , k y_{i,t,k} yi,t,k名临时工。其中, x i , t , k x_{i,t,k} xi,t,k和 y i , t , k y_{i,t,k} yi,t,k均为非负整数。
根据题目中的要求,每个班次的人数不能超过60,即 x i , t , k + y i , t , k ≤ 60 x_{i,t,k} + y_{i,t,k} \leq 60 xi,t,k+yi,t,k≤60。
另外,每天的货量需求为 d i , t d_{i,t} di,t,其中 d i , t d_{i,t} di,t为非负整数。根据问题2的预测结果,每天的货量需求可能会有变化。
因此,需要满足以下约束条件:
∑
k
=
1
6
x
i
,
t
,
k
+
∑
k
=
1
6
y
i
,
t
,
k
=
d
i
,
t
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
\sum_{k=1}^{6} x_{i,t,k} + \sum_{k=1}^{6} y_{i,t,k} = d_{i,t} \quad i = 1,2,\dots,57; t = 1,2,\dots,30
k=1∑6xi,t,k+k=1∑6yi,t,k=di,ti=1,2,…,57;t=1,2,…,30
即每个分拣中心每天的总人数等于当天的货量需求。
另外,每个班次的正式工人数不能超过25,临时工人数不能超过20,即:
x
i
,
t
,
k
≤
25
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
x_{i,t,k} \leq 25 \quad i = 1,2,\dots,57; t = 1,2,\dots,30; k = 1,2,\dots,6
xi,t,k≤25i=1,2,…,57;t=1,2,…,30;k=1,2,…,6
y
i
,
t
,
k
≤
20
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
y_{i,t,k} \leq 20 \quad i = 1,2,\dots,57; t = 1,2,\dots,30; k = 1,2,\dots,6
yi,t,k≤20i=1,2,…,57;t=1,2,…,30;k=1,2,…,6
另外,为了保证每天的实际小时人效尽量均衡,可以设置以下约束条件:
∑
i
=
1
57
x
i
,
t
,
k
+
∑
i
=
1
57
y
i
,
t
,
k
≥
1
6
∑
i
=
1
57
d
i
,
t
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
\sum_{i=1}^{57} x_{i,t,k} + \sum_{i=1}^{57} y_{i,t,k} \geq \frac{1}{6} \sum_{i=1}^{57} d_{i,t} \quad t = 1,2,\dots,30; k = 1,2,\dots,6
i=1∑57xi,t,k+i=1∑57yi,t,k≥61i=1∑57di,tt=1,2,…,30;k=1,2,…,6
这个约束条件表示,每天的总人数至少要达到当天货量需求的六分之一,从而保证每天的实际小时人效不会过低。
综合以上约束条件,可以建立如下优化模型:
min
∑
t
=
1
30
∑
k
=
1
6
(
∑
i
=
1
57
y
i
,
t
,
k
)
s
.
t
.
x
i
,
t
,
k
+
y
i
,
t
,
k
≤
60
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
\min \sum_{t=1}^{30} \sum_{k=1}^{6} \left( \sum_{i=1}^{57} y_{i,t,k}\right) \quad \mathrm{s.t.} \quad x_{i,t,k} + y_{i,t,k} \leq 60 \quad i = 1,2,\dots,57; t = 1,2,\dots,30; k = 1,2,\dots,6
mint=1∑30k=1∑6(i=1∑57yi,t,k)s.t.xi,t,k+yi,t,k≤60i=1,2,…,57;t=1,2,…,30;k=1,2,…,6
∑
k
=
1
6
x
i
,
t
,
k
+
∑
k
=
1
6
y
i
,
t
,
k
=
d
i
,
t
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
\sum_{k=1}^{6} x_{i,t,k} + \sum_{k=1}^{6} y_{i,t,k} = d_{i,t} \quad i = 1,2,\dots,57; t = 1,2,\dots,30
k=1∑6xi,t,k+k=1∑6yi,t,k=di,ti=1,2,…,57;t=1,2,…,30
x
i
,
t
,
k
≤
25
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
x_{i,t,k} \leq 25 \quad i = 1,2,\dots,57; t = 1,2,\dots,30; k = 1,2,\dots,6
xi,t,k≤25i=1,2,…,57;t=1,2,…,30;k=1,2,…,6
y
i
,
t
,
k
≤
20
i
=
1
,
2
,
…
,
57
;
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
y_{i,t,k} \leq 20 \quad i = 1,2,\dots,57; t = 1,2,\dots,30; k = 1,2,\dots,6
yi,t,k≤20i=1,2,…,57;t=1,2,…,30;k=1,2,…,6
∑
i
=
1
57
x
i
,
t
,
k
+
∑
i
=
1
57
y
i
,
t
,
k
≥
1
6
∑
i
=
1
57
d
i
,
t
t
=
1
,
2
,
…
,
30
;
k
=
1
,
2
,
…
,
6
\sum_{i=1}^{57} x_{i,t,k} + \sum_{i=1}^{57} y_{i,t,k} \geq \frac{1}{6} \sum_{i=1}^{57} d_{i,t} \quad t = 1,2,\dots,30; k = 1,2,\dots,6
i=1∑57xi,t,k+i=1∑57yi,t,k≥61i=1∑57di,tt=1,2,…,30;k=1,2,…,6
其中,
d
i
,
t
d_{i,t}
di,t为未来第
t
t
t天第
k
k
k个班次分拣中心
i
i
i的货量预测值。
以上模型的目标函数表示总的临时工人数,约束条件保证了每天的货量需求得到满足,并且保证了每天的实际小时人效尽可能均衡,从而实现了尽可能降低总人天数,平衡每天的实际小时人效的目标。
最后,可以使用数学规划软件(如LINGO、GAMS等)求解以上模型,得到每个分拣中心每个班次的出勤人数。根据出勤人数和分拣中心的正式工和临时工的人数,可以计算出需要雇佣的临时工人数,并写入结果表5中。
问题3:分拣中心人员排班模型
假设每个分拣中心有 n n n名正式工和 m m m名临时工。根据问题描述,正式工和临时工每天只能出勤一个班次,且正式工的最高小时人效为25包裹/小时,临时工的最高小时人效为20包裹/小时。设第 i i i个分拣中心第 j j j个班次需要安排 p i j p_{ij} pij名正式工和 q i j q_{ij} qij名临时工。根据题目要求,每天的工作量(包裹量)应该由正式工和临时工共同承担,且每天的实际小时人效应尽量均衡。因此,可以建立如下数学模型:
目标函数:
min
∑
i
=
1
n
∑
j
=
1
6
(
p
i
j
+
q
i
j
)
\min \sum_{i=1}^{n}\sum_{j=1}^{6}(p_{ij}+q_{ij})
min∑i=1n∑j=16(pij+qij)
约束条件:
1)每天每个班次的工作量应该等于每天的总工作量:
∑ i = 1 n ( p i j ⋅ 25 + q i j ⋅ 20 ) = d j , j = 1 , 2 , 3 , 4 , 5 , 6 \sum_{i=1}^{n}(p_{ij}\cdot 25+q_{ij}\cdot 20)=d_j,\ j=1,2,3,4,5,6 ∑i=1n(pij⋅25+qij⋅20)=dj, j=1,2,3,4,5,6
其中, d j d_j dj为第 j j j个班次的货量预测值。
2)每个分拣中心每天只能出勤一个班次:
∑ j = 1 6 ( p i j + q i j ) = 1 , i = 1 , 2 , . . . , n \sum_{j=1}^{6}(p_{ij}+q_{ij})=1,\ i=1,2,...,n ∑j=16(pij+qij)=1, i=1,2,...,n
3)正式工和临时工的数量不能超过分拣中心的总人数:
p i j ≤ n i , q i j ≤ m i , i = 1 , 2 , . . . , n , j = 1 , 2 , . . . , 6 p_{ij}\leq n_i,\ q_{ij}\leq m_i,\ i=1,2,...,n,\ j=1,2,...,6 pij≤ni, qij≤mi, i=1,2,...,n, j=1,2,...,6
其中, n i n_i ni为第 i i i个分拣中心的正式工总人数, m i m_i mi为第 i i i个分拣中心的临时工总人数。
4)每名正式工的出勤率不能高于85%,且连续出勤天数不能超过7天:
∑ j = 1 6 p i j ≤ 0.85 ⋅ 30 , i = 1 , 2 , . . . , n \sum_{j=1}^{6}p_{ij}\leq 0.85\cdot 30,\ i=1,2,...,n ∑j=16pij≤0.85⋅30, i=1,2,...,n
∑ k = i i + 6 ∑ j = 1 6 p k j ≤ 7 , i = 1 , 2 , . . . , n − 6 \sum_{k=i}^{i+6}\sum_{j=1}^{6}p_{kj}\leq 7,\ i=1,2,...,n-6 ∑k=ii+6∑j=16pkj≤7, i=1,2,...,n−6
5)每天的实际小时人效尽量均衡:
∑ i = 1 n ( p i j ⋅ 25 + q i j ⋅ 20 ) = 1 6 ∑ i = 1 n ∑ j = 1 6 ( p i j ⋅ 25 + q i j ⋅ 20 ) , j = 1 , 2 , 3 , 4 , 5 , 6 \sum_{i=1}^{n}(p_{ij}\cdot 25+q_{ij}\cdot 20)=\frac{1}{6}\sum_{i=1}^{n}\sum_{j=1}^{6}(p_{ij}\cdot 25+q_{ij}\cdot 20),\ j=1,2,3,4,5,6 ∑i=1n(pij⋅25+qij⋅20)=61∑i=1n∑j=16(pij⋅25+qij⋅20), j=1,2,3,4,5,6
6)每天每个班次的出勤人数应该为整数:
p i j , q i j ∈ Z + , i = 1 , 2 , . . . , n , j = 1 , 2 , . . . , 6 p_{ij}, q_{ij} \in \mathbb{Z}^+,\ i=1,2,...,n,\ j=1,2,...,6 pij,qij∈Z+, i=1,2,...,n, j=1,2,...,6
7)每个分拣中心每天的人员安排应该满足分拣中心的最大工作量:
∑ j = 1 6 ( p i j ⋅ 25 + q i j ⋅ 20 ) ≤ c i , i = 1 , 2 , . . . , n \sum_{j=1}^{6}(p_{ij}\cdot 25+q_{ij}\cdot 20)\leq c_i,\ i=1,2,...,n ∑j=16(pij⋅25+qij⋅20)≤ci, i=1,2,...,n
其中, c i c_i ci为第 i i i个分拣中心的最大工作量。
综上所述,可以建立如下最小化问题:
min ∑ i = 1 n ∑ j = 1 6 ( p i j + q i j ) \min \sum_{i=1}^{n}\sum_{j=1}^{6}(p_{ij}+q_{ij}) min∑i=1n∑j=16(pij+qij)
s.t. ∑ i = 1 n ( p i j ⋅ 25 + q i j ⋅ 20 ) = d j , j = 1 , 2 , 3 , 4 , 5 , 6 \text{s.t.} \quad \sum_{i=1}^{n}(p_{ij}\cdot 25+q_{ij}\cdot 20)=d_j,\ j=1,2,3,4,5,6 s.t.∑i=1n(pij⋅25+qij⋅20)=dj, j=1,2,3,4,5,6
∑ j = 1 6 ( p i j + q i j ) = 1 , i = 1 , 2 , . . . , n \sum_{j=1}^{6}(p_{ij}+q_{ij})=1,\ i=1,2,...,n ∑j=16(pij+qij)=1, i=1,2,...,n
p i j ≤ n i , q i j ≤ m i , i = 1 , 2 , . . . , n , j = 1 , 2 , . . . , 6 p_{ij}\leq n_i,\ q_{ij}\leq m_i,\ i=1,2,...,n,\ j=1,2,...,6 pij≤ni, qij≤mi, i=1,2,...,n, j=1,2,...,6
∑ j = 1 6 p i j ≤ 0.85 ⋅ 30 , i = 1 , 2 , . . . , n \sum_{j=1}^{6}p_{ij}\leq 0.85\cdot 30,\ i=1,2,...,n ∑j=16pij≤0.85⋅30, i=1,2,...,n
∑ k = i i + 6 ∑ j = 1 6 p k j ≤ 7 , i = 1 , 2 , . . . , n − 6 \sum_{k=i}^{i+6}\sum_{j=1}^{6}p_{kj}\leq 7,\ i=1,2,...,n-6 ∑k=ii+6∑j=16pkj≤7, i=1,2,...,n−6
∑ i = 1 n ( p i j ⋅ 25 + q i j ⋅ 20 ) = 1 6 ∑ i = 1 n ∑ j = 1 6 ( p i j ⋅ 25 + q i j ⋅ 20 ) , j = 1 , 2 , 3 , 4 , 5 , 6 \sum_{i=1}^{n}(p_{ij}\cdot 25+q_{ij}\cdot 20)=\frac{1}{6}\sum_{i=1}^{n}\sum_{j=1}^{6}(p_{ij}\cdot 25+q_{ij}\cdot 20),\ j=1,2,3,4,5,6 ∑i=1n(pij⋅25+qij⋅20)=61∑i=1n∑j=16(pij⋅25+qij⋅20), j=1,2,3,4,5,6
p i j , q i j ∈ Z + , i = 1 , 2 , . . . , n , j = 1 , 2 , . . . , 6 p_{ij}, q_{ij} \in \mathbb{Z}^+,\ i=1,2,...,n,\ j=1,2,...,6 pij,qij∈Z+, i=1,2,...,n, j=1,2,...,6
∑ j = 1 6 ( p i j ⋅ 25 + q i j ⋅ 20 ) ≤ c i , i = 1 , 2 , . . . , n \sum_{j=1}^{6}(p_{ij}\cdot 25+q_{ij}\cdot 20)\leq c_i,\ i=1,2,...,n ∑j=16(pij⋅25+qij⋅20)≤ci, i=1,2,...,n
其中, p i j p_{ij} pij为第 i i i个分拣中心第 j j j个班次安排的正式工人数, q i j q_{ij} qij为第 i i i个分拣中心第 j j j个班次安排的临时工人数, d j d_j dj为第 j j j个班次的货量预测值, n i n_i ni为第 i i i个分拣中心的正式工总人数, m i m_i mi为第 i i i个分拣中心的临时工总人数, c i c_i ci为第 i i i个分拣中心的最大工作量。
该问题可以通过线性规划方法求解,得到最优解即为每个分拣中心每个班次需要安排的正式工和临时工人数。
# 导入所需的库
import pandas as pd
import numpy as np
from scipy.optimize import minimize
# 读取数据
df_vol_day = pd.read_excel('附件1:分拣中心历史订单数据.xlsx', sheet_name='按天统计')
df_vol_hour = pd.read_excel('附件2:分拣中心历史订单数据.xlsx', sheet_name='按小时统计')
df_line_vol = pd.read_excel('附件3:过去90天各分拣中心之间的各运输线路平均货量.xlsx')
df_line_change = pd.read_excel('附件4:未来30天分拣中心之间的运输线路变化.xlsx')
# 定义需要用到的函数
# 计算每个分拣中心每天的总货量
def cal_total_vol(df):
df['总货量'] = df['00:00-24:00'].apply(lambda x: np.sum(x))
return df
# 计算每个分拣中心每小时的总货量
def cal_total_vol_hour(df):
df['总货量'] = df['00:00'].apply(lambda x: np.sum(x))
return df
# 计算每个分拣中心每天所需的人数
def cal_person_day(df, person_efficiency):
df['所需人数'] = np.ceil(df['总货量'] / (person_efficiency * 24))
return df
# 计算每个分拣中心每小时所需的人数
def cal_person_hour(df, person_efficiency):
df['所需人数'] = np.ceil(df['总货量'] / person_efficiency)
return df
# 计算每个班次的总人数
def cal_total_person(df):
df['总人数'] = df['所需人数'].apply(lambda x: np.sum(x))
return df
# 定义目标函数
# 目标函数为总人数最小化
def objective(x):
return np.sum(x)
# 定义约束条件
# 约束条件为每天的实际小时人效尽量均衡
def constraint1(x):
return np.mean(x[:6]) - np.mean(x[6:12])
# 约束条件为正式工出勤率尽量均衡
def constraint2(x):
return np.mean(x[:6]) - np.mean(x[6:12])
# 约束条件为连续出勤天数不能超过7天
def constraint3(x):
for i in range(len(x)-7):
if np.sum(x[i:i+7]) > 6:
return np.sum(x[i:i+7]) - 6
return 0
# 定义初值
# 初值为每个班次的总人数的一半
x0 = [df_line_vol['总人数'][i]/2 for i in range(12)]
# 定义约束条件
cons = ({'type': 'eq', 'fun': constraint1},
{'type': 'eq', 'fun': constraint2},
{'type': 'ineq', 'fun': constraint3})
# 定义结果表
df_result = pd.DataFrame(columns=['分拣中心', '班次', '人数'])
# 循环求解
for i in range(len(df_line_vol)):
# 构造目标函数的参数
df = df_vol_day[df_vol_day['分拣中心'] == df_line_vol['分拣中心'][i]]
# 计算每个分拣中心的总货量
df = cal_total_vol(df)
# 计算每个分拣中心每天所需的人数
df = cal_person_day(df, df_line_vol['正式工小时人效'][i])
# 计算每个班次的总人数
df = cal_total_person(df)
# 求解
res = minimize(objective, x0=x0, constraints=cons, method='SLSQP')
# 将结果写入结果表
# 正式工
for j in range(6):
df_result = df_result.append([{'分拣中心': df_line_vol['分拣中心'][i], '班次': j+1, '人数': res.x[j]}])
# 临时工
for j in range(6, 12):
df_result = df_result.append([{'分拣中心': df_line_vol['分拣中心'][i], '班次': j+1, '人数': res.x[j]}])
df_result.reset_index(drop=True, inplace=True)
# 输出结果表
df_result.to_excel('结果表5.xlsx', index=False)
该段文字的第四个问题是:请基于问题2的预测结果建立模型,确定未来30天每名正式工及临时工的班次出勤计划。
假设分拣中心SC60当前有 N N N名正式工,其中每人每天出勤的班次为 M M M,则每名正式工的总出勤班次数为 30 × M 30 \times M 30×M。
设第 i i i名正式工在第 j j j天出勤的班次为 x i j x_{ij} xij,其中 x i j x_{ij} xij为0或1,表示第 i i i名正式工在第 j j j天是否出勤。
设每个班次需要雇佣的临时工人数为 y j y_j yj,其中 y j y_j yj为非负整数。
目标函数为最小化总人天数:
min
∑
i
=
1
N
∑
j
=
1
30
x
i
j
+
∑
j
=
1
30
y
j
\min \sum_{i=1}^{N} \sum_{j=1}^{30} x_{ij} + \sum_{j=1}^{30} y_j
mini=1∑Nj=1∑30xij+j=1∑30yj
约束条件为:
∑
j
=
1
30
x
i
j
=
30
×
M
(
i
=
1
,
2
,
.
.
.
,
N
)
\sum_{j=1}^{30} x_{ij} = 30 \times M \;\; (i=1,2,...,N)
j=1∑30xij=30×M(i=1,2,...,N)
每名正式工必须出勤的总班次数为30。
x
i
j
≤
1
(
i
=
1
,
2
,
.
.
.
,
N
;
j
=
1
,
2
,
.
.
.
,
30
)
x_{ij} \leq 1 \;\; (i=1,2,...,N; j=1,2,...,30)
xij≤1(i=1,2,...,N;j=1,2,...,30)
每名正式工每天只能出勤一个班次。
∑
i
=
1
N
x
i
j
+
y
j
=
预测的第
j
天的总货量
/
正式工的最高小时人效
(
j
=
1
,
2
,
.
.
.
,
30
)
\sum_{i=1}^{N} x_{ij} + y_j = 预测的第j天的总货量 / 正式工的最高小时人效 \;\; (j=1,2,...,30)
i=1∑Nxij+yj=预测的第j天的总货量/正式工的最高小时人效(j=1,2,...,30)
根据预测结果,每天的总货量应该由正式工和临时工共同完成,且每天的总工作量不能超过正式工的最高小时人效。
∑
i
=
1
N
x
k
j
=
∑
i
=
1
N
x
l
j
(
j
=
1
,
2
,
.
.
.
,
30
;
k
,
l
=
1
,
2
,
.
.
.
,
N
;
k
≠
l
)
\sum_{i=1}^{N} x_{kj} = \sum_{i=1}^{N} x_{lj} \;\; (j=1,2,...,30; k,l=1,2,...,N; k \neq l)
i=1∑Nxkj=i=1∑Nxlj(j=1,2,...,30;k,l=1,2,...,N;k=l)
每天各个班次的正式工人数应该尽量均衡。
∑
i
=
1
N
x
i
j
≤
0.85
×
30
(
i
=
1
,
2
,
.
.
.
,
N
;
j
=
1
,
2
,
.
.
.
,
30
)
\sum_{i=1}^{N} x_{ij} \leq 0.85 \times 30 \;\; (i=1,2,...,N; j=1,2,...,30)
i=1∑Nxij≤0.85×30(i=1,2,...,N;j=1,2,...,30)
每名正式工的出勤率不能高于85%。
∑
i
=
1
N
x
i
j
≤
7
(
i
=
1
,
2
,
.
.
.
,
N
;
j
=
1
,
2
,
.
.
.
,
24
)
\sum_{i=1}^{N} x_{ij} \leq 7 \;\; (i=1,2,...,N; j=1,2,...,24)
i=1∑Nxij≤7(i=1,2,...,N;j=1,2,...,24)
每名正式工连续出勤的天数不能超过7天。
x
i
j
∈
{
0
,
1
}
(
i
=
1
,
2
,
.
.
.
,
N
;
j
=
1
,
2
,
.
.
.
,
30
)
x_{ij} \in \{0,1\} \;\; (i=1,2,...,N; j=1,2,...,30)
xij∈{0,1}(i=1,2,...,N;j=1,2,...,30)
y
j
∈
Z
+
(
j
=
1
,
2
,
.
.
.
,
30
)
y_j \in \mathbb{Z}^+ \;\; (j=1,2,...,30)
yj∈Z+(j=1,2,...,30)
以上模型可以通过线性规划求解,得出每名正式工在每天六个班次中的出勤情况,以及每个班次需要雇佣的临时工人数。
问题4的模型可以建立如下:
假设每名正式工的出勤情况为一个三维向量 A = ( a 1 , a 2 , . . . , a 30 ) A = (a_1, a_2, ..., a_{30}) A=(a1,a2,...,a30),其中 a i a_i ai表示第 i i i天该正式工是否出勤, a i ∈ { 0 , 1 } a_i \in \{0, 1\} ai∈{0,1}。同样,假设临时工的出勤情况为一个三维向量 B = ( b 1 , b 2 , . . . , b 30 ) B = (b_1, b_2, ..., b_{30}) B=(b1,b2,...,b30),其中 b i b_i bi表示第 i i i天该临时工是否出勤, b i ∈ { 0 , 1 } b_i \in \{0, 1\} bi∈{0,1}。
根据题目要求,正式工的出勤率不能高于85%,即 ∑ i = 1 30 a i 30 ≤ 0.85 \frac{\sum_{i=1}^{30}a_i}{30} \leq 0.85 30∑i=130ai≤0.85。同时,连续出勤天数不能超过7天,即 a i = 1 a_i = 1 ai=1时, a i + 1 = a i + 2 = . . . = a i + 6 = 1 a_{i+1} = a_{i+2} = ... = a_{i+6} = 1 ai+1=ai+2=...=ai+6=1。
因此,可以建立如下优化问题:
max A , B ∑ i = 1 30 b i s.t. ∑ i = 1 30 a i 30 ≤ 0.85 a i = 1 ⇒ a i + 1 = a i + 2 = . . . = a i + 6 = 1 a i ∈ { 0 , 1 } , b i ∈ { 0 , 1 } , ∀ i ∈ { 1 , 2 , . . . , 30 } \begin{aligned} \max_{A, B} \quad & \sum_{i=1}^{30} b_i \\ \text{s.t.} \quad & \frac{\sum_{i=1}^{30}a_i}{30} \leq 0.85 \\ & a_i = 1 \Rightarrow a_{i+1} = a_{i+2} = ... = a_{i+6} = 1 \\ & a_i \in \{0, 1\}, b_i \in \{0, 1\}, \forall i \in \{1, 2, ..., 30\} \end{aligned} A,Bmaxs.t.i=1∑30bi30∑i=130ai≤0.85ai=1⇒ai+1=ai+2=...=ai+6=1ai∈{0,1},bi∈{0,1},∀i∈{1,2,...,30}
该优化问题的目标函数为最小化临时工的使用量,约束条件为正式工的出勤率和连续出勤天数的限制。通过求解上述优化问题,可以得到每名正式工和临时工在未来30天每天的出勤情况,从而确定分拣中心SC60的排班计划。
值得注意的是,该模型可以根据具体情况进行调整和优化,例如可以加入正式工和临时工的出勤效率、工作量等因素,进一步提高排班的效率和公平性。
问题4:建立模型,确定未来30天每名正式工及临时工的班次出勤计划。
设分拣中心SC60共有N名正式工和M名临时工,每天分为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。
假设每名正式工的出勤率为p,每天有K名临时工被雇佣。
根据问题2的预测结果,分拣中心SC60在未来30天每天的货量为L天,即每天需要进行分拣的包裹数量。
假设每名正式工的小时人效为x,每名临时工的小时人效为y,则每天需求的工作时间为 T = L / x + ( K / M ) ∗ y T=L/x+(K/M)*y T=L/x+(K/M)∗y。
在给定每天的工作时间限制下,需要求解的问题是如何安排每名正式工和临时工的班次出勤,使得总人天数最小。
这是一个典型的排班问题,可以使用线性规划求解。
假设每名正式工参加班次i的概率为pi,每名临时工参加班次i的概率为qi,则有以下约束条件:
-
每名正式工每天只能出勤一个班次,每名临时工每天只能出勤一个班次:∑i=1,6pi=1,∑i=1,6qi=1。
-
每名正式工的出勤率不超过85%:∑i=1,30pi≤0.85。
-
每名正式工连续出勤天数不超过7天:∑i=1,6pi≤1,∑i=1,6pi+∑i=7,12pi≤1,…,∑i=25,30pi≤1。
-
每天的工作时间限制:∑i=1,6piT+(K/M)∑i=1,6qiT=∑i=1,6piT+(K/M)∑i=1,6qiT。
-
每天的班次人数限制:∑i=1,6pi+∑i=1,6qi=K。
-
每天的实际小时人效尽量均衡:∑i=1,6pix+∑i=1,6qiy=∑i=1,6pix+∑i=1,6qiy。
目标函数为最小化总人天数:∑i=1,30pi。
根据以上约束条件,可以构建线性规划模型,使用求解软件求解得到每名正式工和临时工的班次出勤计划。
具体的数学公式如下:
minimize ∑ i = 1 30 p i subject to ∑ i = 1 6 p i = 1 ∑ i = 1 6 q i = 1 ∑ i = 1 30 p i ≤ 0.85 ∑ i = 1 6 p i ≤ 1 ∑ i = 1 6 p i + ∑ i = 7 12 p i ≤ 1 ⋯ ∑ i = 25 30 p i ≤ 1 ∑ i = 1 6 p i ∗ T + K M ∑ i = 1 6 q i ∗ T = ∑ i = 1 6 p i ∗ T + K M ∑ i = 1 6 q i ∗ T ∑ i = 1 6 p i + ∑ i = 1 6 q i = K ∑ i = 1 6 p i ∗ x + ∑ i = 1 6 q i ∗ y = ∑ i = 1 6 p i ∗ x + ∑ i = 1 6 q i ∗ y \begin{equation} \begin{aligned} &\text{minimize } && \sum_{i=1}^{30}p_i \\ &\text{subject to} && \sum_{i=1}^{6}p_i = 1 \\ &&& \sum_{i=1}^{6}q_i = 1 \\ &&& \sum_{i=1}^{30}p_i \leq 0.85 \\ &&& \sum_{i=1}^{6}p_i \leq 1 \\ &&& \sum_{i=1}^{6}p_i + \sum_{i=7}^{12}p_i \leq 1 \\ &&& \cdots \\ &&& \sum_{i=25}^{30}p_i \leq 1 \\ &&& \sum_{i=1}^{6}p_i*T + \frac{K}{M}\sum_{i=1}^{6}q_i*T = \sum_{i=1}^{6}p_i*T + \frac{K}{M}\sum_{i=1}^{6}q_i*T \\ &&& \sum_{i=1}^{6}p_i + \sum_{i=1}^{6}q_i = K \\ &&& \sum_{i=1}^{6}p_i*x + \sum_{i=1}^{6}q_i*y = \sum_{i=1}^{6}p_i*x + \sum_{i=1}^{6}q_i*y \\ \end{aligned} \end{equation} minimize subject toi=1∑30pii=1∑6pi=1i=1∑6qi=1i=1∑30pi≤0.85i=1∑6pi≤1i=1∑6pi+i=7∑12pi≤1⋯i=25∑30pi≤1i=1∑6pi∗T+MKi=1∑6qi∗T=i=1∑6pi∗T+MKi=1∑6qi∗Ti=1∑6pi+i=1∑6qi=Ki=1∑6pi∗x+i=1∑6qi∗y=i=1∑6pi∗x+i=1∑6qi∗y
其中, p i p_i pi为第 i i i天每名正式工参加班次的概率, q i q_i qi为第 i i i天每名临时工参加班次的概率, T T T为每天的工作时间, K K K为每天雇佣的临时工数量, M M M为总的临时工数量, x x x为每名正式工的小时人效, y y y为每名临时工的小时人效。
根据以上模型,可以求解出每名正式工和临时工的班次出勤计划,并将结果写入结果表6中。
# 导入数据
import pandas as pd
import numpy as np
# 读取附件1-4数据
data1 = pd.read_excel('附件1.xlsx') # 过去4个月每天货量
data2 = pd.read_excel('附件2.xlsx') # 过去30天每小时货量
data3 = pd.read_excel('附件3.xlsx') # 过去90天各分拣中心之间的各运输线路平均货量
data4 = pd.read_excel('附件4.xlsx') # 未来30天分拣中心之间的运输线路变化情况
# 数据预处理
# 附件1
# 将日期和分拣中心作为索引
data1.set_index(['日期', '分拣中心'], inplace=True)
# 转置数据,行索引为日期,列索引为分拣中心
data1 = data1.T
# 将日期和分拣中心作为索引
data1.index.names = ['日期', '分拣中心']
# 附件2
# 将日期和分拣中心作为索引
data2.set_index(['日期', '分拣中心'], inplace=True)
# 转置数据,行索引为日期,列索引为分拣中心
data2 = data2.T
# 将日期和分拣中心作为索引
data2.index.names = ['日期', '分拣中心']
# 附件3
# 将分拣中心作为索引
data3.set_index(['分拣中心'], inplace=True)
# 转置数据,行索引为分拣中心,列索引为分拣中心
data3 = data3.T
# 将分拣中心作为索引
data3.index.names = ['分拣中心']
# 附件4
# 将分拣中心作为索引
data4.set_index(['分拣中心'], inplace=True)
# 转置数据,行索引为分拣中心,列索引为分拣中心
data4 = data4.T
# 将分拣中心作为索引
data4.index.names = ['分拣中心']
# 创建结果表6
# 以分拣中心为索引,以日期为列索引
result6 = pd.DataFrame(index=data1.columns, columns=data1.index.levels[0])
# 将分拣中心和日期作为索引
result6.index.names = ['分拣中心', '日期']
# 定义函数进行每日人员排班
def schedule(date):
# 获取当日分拣中心的预测货量
prediction = result2.loc[date]
# 获取当日分拣中心之间的运输线路变化情况
route_change = data4.loc[date]
# 获取当日分拣中心之间的运输线路平均货量
route_avg = data3.loc[date]
# 初始化每日分拣中心的正式工和临时工出勤人数
official_worker = pd.Series(index=data1.index.levels[1], data=0)
temporary_worker = pd.Series(index=data1.index.levels[1], data=0)
# 对每个分拣中心进行遍历
for center in data1.index.levels[1]:
# 获取当日该分拣中心的预测货量
center_prediction = prediction[center]
# 获取当日该分拣中心之间的运输线路变化情况
center_route_change = route_change[center]
# 获取当日该分拣中心之间的运输线路平均货量
center_route_avg = route_avg[center]
# 计算当日该分拣中心需要的总人数
total_worker = center_prediction.sum() + center_route_change.sum() + center_route_avg.sum()
# 获取该分拣中心当前的正式工和临时工出勤人数
current_official_worker = result6.loc[(center, date)].sum()
current_temporary_worker = result6.loc[(center, date)].size - current_official_worker
# 计算该分拣中心还需要的临时工人数
need_temporary_worker = total_worker - current_official_worker - current_temporary_worker
# 判断是否需要额外招募临时工
if need_temporary_worker > 0:
# 计算该分拣中心当前的正式工出勤率
current_official_worker_attendance = current_official_worker / 6
# 计算该分拣中心每个班次需要的临时工人数
temporary_worker_per_shift = int(np.ceil(need_temporary_worker / 6))
# 根据该分拣中心当前的正式工出勤率,确定每个班次需要多少正式工出勤
for s in range(6):
# 判断该班次是否需要额外雇佣临时工
if center_route_avg[s] > 0:
# 额外雇佣的临时工人数
extra_temporary_worker = temporary_worker_per_shift
# 判断该班次是否需要额外的正式工出勤
if center_route_avg[s] > current_official_worker_attendance:
# 额外需要的正式工出勤人数
extra_official_worker = int(np.ceil(center_route_avg[s] - current_official_worker_attendance))
else:
extra_official_worker = 0
# 更新该班次的正式工和临时工出勤人数
official_worker[center] += extra_official_worker
temporary_worker[center] += extra_temporary_worker
# 返回当日分拣中心的出勤人数
return official_worker, temporary_worker
# 对每天进行遍历
for date in data1.index.levels[0]:
# 获取当日分拣中心的正式工和临时工出勤人数
official_worker, temporary_worker = schedule(date)
# 将当日分拣中心的正式工和临时工出勤人数写入结果表6
result6.loc[(slice(None), date), '正式工'] = official_worker
result6.loc[(slice(None), date), '临时工'] = temporary_worker
# 对每个分拣中心进行遍历
for center in data1.index.levels[1]:
# 获取该分拣中心的正式工出勤率
official_worker_attendance = result6.loc[center, '正式工'].sum() / 180
# 初始化该分拣中心每个班次的临时工出勤人数
temporary_worker_per_shift = pd.Series(index=range(6), data=0)
# 对每个班次进行遍历
for s in range(6):
# 获取当日该分拣中心的预测货量
center_prediction = result2.loc[(slice(None), center), s]
# 获取当日该分拣中心的正式工出勤人数
center_official_worker = result6.loc[(center, slice(None)), '正式工'].sum()
# 计算该班次需要额外的临时工人数
temporary_worker_per_shift[s] = int(np.ceil((center_prediction - center_official_worker_attendance * center_prediction) / 20))
# 将该分拣中心每个班次的临时工出勤人数写入结果表6
result6.loc[(center, slice(None)), '临时工'] = temporary_worker_per_shift
# 将结果表6写入文件
result6.to_excel('结果表6.xlsx')
更多内容可以点击下方名片详细了解,让小鹿学长带你冲刺Mathorcup夺奖之路!
敬请期待我们的努力所做出的工作!记得关注 鹿鹿学长呀!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)