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名片即可
部分程序代碼:
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.csvdaily_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_dfdef preprocess_daily(data):"""每日數據預處理"""# 缺失值處理(前向填充)data = data.fillna(method='ffill')# 添加時間特征data['day_of_week'] = data['date'].dt.dayofweekdata['is_holiday'] = data['date'].isin(holiday_dates) # 需定義節假日列表data['days_to_promotion'] = (data['date'] - pd.to_datetime("2023-11-01")).dt.daysreturn datadef 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] = resultdef predict(self, center_id, steps=30):model = self.models[center_id]forecast = model.get_forecast(steps=steps)return forecast.predicted_meanclass 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] = modeldef 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()# 生成每日預測結果表1daily_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# 生成每小時預測結果表2hourly_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)