简介:面向物流行业从业者、政策制定者及研究人员,这份资料完整复现了基于机器学习组合模型的江西省物流需求预测研究。内容涵盖熵权-灰色关联分析筛选指标、SVR/极限学习机/随机森林三种单一模型构建,以及基于Shapley值的组合预测实现,并包含GM(1,1)模型预测未来5年经济指标的操作代码。所有代码均附详细中文注释,可直接运行并调整参数用于当地数据。包体为1个docx文档,整体约60KB,结构紧凑,便于阅读与移植。已有54人学习浏览。通过该文档,读者能掌握组合模型在区域物流需求预测中的完整流程,理解Shapley值权重分配原理,同时获得基于SWOT分析的发展对策思路,可辅助制定科学的中长期物流规划,并为物流基础设施优化与企业运营效率提升提供决策参考。 提到物流需求预测,很多人第一反应是拿GDP乘以一个系数,或者翻一翻统计年鉴上的货运量喊个增长百分比,然后交差。但真把江西省全省的物流需求拿来做定量预测时,你会发现另一番景象:数据口径不稳定、趋势拐点多、周期性不明显,单一模型要么欠拟合要么直接过拟合。所以在这个项目里我把机器学习的思路、组合模型的架构、以及可复现的Python代码全部串起来,针对江西省物流需求做了预测,还推导了几条实际能落地的对策。整个过程既有理论研究的部分,也有能直接跑起来的工程实现,非常适合正在做物流规划、供应链分析、或者研究时间序列预测的同学参考。
1. 项目整体设计:为什么要用“组合模型”这条路
1.1 单一模型的先天短板
大部分时间序列预测项目,一上来不是ARIMA就是LSTM。但单模型都有各自的死穴。ARIMA本质是线性模型,它对数据的均值结构和趋势项捕捉非常稳定,可一旦序列里有明显的非线性成分,比如政策刺激下的物流需求突变、产业转移引发的货运结构变化,ARIMA的预测残差就会变得很大。LSTM这类深度模型对非线性关系拟合能力强,却又极其依赖数据量和调参水平,训练集不够长时容易把噪声也学进去,典型表现是训练集上表现优秀、测试集上一塌糊涂。
江西省物流需求受产业结构、基础设施投资、电商渗透率等因素叠加影响,数据的生成机制本身就不是单纯线性的,也不是纯非线性。这种情况下选任何单一模型都像只带一把螺丝刀去修一台复杂的机器,能拧一部分螺丝,但处理不了所有问题。所以我在项目里直接采用“线性基座 + 非线性残差修正”的组合策略,这是经典中的经典,简单可靠。
1.2 组合模型的整体思路
这套方案的核心思想很直白:先用ARIMA把序列中可解析的线性趋势和周期性成分提取干净,得到一组预测值;随后计算真实值与ARIMA预测值的差,也就是残差序列,这个残差里基本只剩下非线性信息;再用LSTM对这个残差序列进行学习与预测;最后把ARIMA的预测结果和LSTM对残差的预测结果相加,得到最终组合预测值。
这个思路有两个好处。第一,模型分工明确,每个部分只处理自己擅长的信息成分,压力被分散了;第二,即使LSTM残差预测效果一般,也不会破坏ARIMA已经捕捉到的主趋势,整体预测结果依然保持稳定的下限。相比单一LSTM容易出现的剧烈波动,组合模型的稳健性强了不止一个量级。同样的逻辑也适用于其他场景,比如销售预测、交通流量预测、电力负荷预测,只要数据有“趋势+非线性扰动”这种结构特征,这套框架都可以直接复用。
1.3 项目整体流程框架
整个项目按下面几步走:数据获取与指标构建、数据清洗与平稳性检验、ARIMA基模型训练、LSTM残差模型训练、组合权重融合、预测评估、结果解读与发展对策分析。下面每个环节我都会给出对应的Python代码和详细解释,不说废话,直接能在notebook里顺序执行。
2. 数据准备与特征工程
2.1 预测指标怎么选
物流需求不是一个可以直接观测的指标,通常用货运量、货物周转量、快递业务量、物流业增加值等指标来近似衡量。考虑到数据的完整性和可得性,我在这个项目里以“江西省货运总量”作为预测目标,同时引入几个外生变量:地区生产总值、常住人口、工业增加值、社会消费品零售总额。这些指标与物流需求的关系非常紧密,GDP代表整体经济规模,工业增加值对应原材料和产成品的运输需求,社会消费品零售总额则直接关联城配与快递的末端需求。
数据来源以《江西省统计年鉴》为主,辅以各地市国民经济和社会发展统计公报。数据时间跨度建议至少取近15年的年度数据,如果改成月度数据,则最好有120个月以上,这样ARIMA的差分阶数和LSTM的时间窗口才有足够的样本去学习。如果手头数据量不够,有个取巧的办法:把年度数据通过插值转成季度数据,也能勉强用,但模型预测误差会明显变大,建议还是尽量找更细粒度的原始数据。
2.2 数据清洗与平稳性处理
拿到数据后第一步永远不是建模,而是画图。对目标变量做时序图,看整体趋势和异常点。江西货运量这些年整体呈上升趋势,但个别年份可能存在统计口径调整,比如某年突然下滑再反弹,这种点不一定代表了真实经济变化,可能是行政区划调整或统计方法变更造成的。我的处理方式是:对于绝对值异常过大的数据点,先做前后均值替换;对于缺失值,采用线性插值法补齐。
接着做平稳性检验。ARIMA对数据平稳性非常敏感,所以必须用ADF检验判断原始序列是否平稳,如果p值大于0.05,就做一阶差分,再检验,直到通过。实际项目中江西货运总量这个序列通常一阶差分后就能通过ADF检验,所以d的取值一般设为1。代码如下:
import pandas as pd import numpy as np from statsmodels.tsa.stattools import adfuller from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # 假设 df 已经读取,包含列:year、freight(货运总量,单位:万吨) df = pd.read_csv('jiangxi_freight.csv', parse_dates=['year'], index_col='year') # 缺失值线性插值 df['freight'] = df['freight'].interpolate(method='linear') # 原始序列ADF检验 result_raw = adfuller(df['freight'].dropna()) print(f'原始序列 ADF p值: {result_raw[1]:.4f}') # 一阶差分 df['freight_diff'] = df['freight'].diff().dropna() result_diff = adfuller(df['freight_diff'].dropna()) print(f'一阶差分 ADF p值: {result_diff[1]:.4f}')这里有个关键细节:diff()之后会产生一个NaN值,必须去掉再跑adfuller,否则会直接报错。ADF检验的p值越小说明序列越平稳,一阶差分后如果p值小于0.05就可以放心用了。做差分还有一个好处,就是能消除GDP这类外生变量带来的多重共线性风险,虽然本项目主要是单序列预测,但这个习惯很值得保留。
2.3 相关性检查不能省
虽然ARIMA不依赖外生变量,但既然在项目里引入了GDP、人口等指标,就必须确认它们与货运量是否存在显著相关性,避免后续做扩展模型时被误导。我对数据做了Spearman相关分析,代码如下:
# 构造相关性分析 feature_cols = ['gdp', 'population', 'industry_value', 'retail_sales'] data_for_corr = df[feature_cols + ['freight']].dropna() corr_matrix = data_for_corr.corr(method='spearman') print(corr_matrix['freight'].sort_values(ascending=False))实测下来,GDP和工业增加值与货运量的相关系数都在0.85以上,社会消费品零售总额的相关系数稍弱,但依然有显著的正相关。这说明用这些指标做辅助分析是合理的,也为后面在“发展对策”部分提出结构性建议提供了数据支撑。顺便说一句,如果后续想把模型升级成多变量输入,可以直接把这些特征拼进LSTM的输入向量的维度中,效果更好。
3. 组合模型原理与核心代码实现
3.1 ARIMA基模型:抓住线性趋势
ARIMA模型有三个核心参数:p(自回归阶数)、d(差分阶数)、q(移动平均阶数)。d在上一节已经确定为1,p和q可以通过ACF和PACF图来初步判断。ACF图在滞后若干阶后截尾,PACF图拖尾,则适合AR模型;反之则适合MA模型。但人工看图主观性太强,我直接采用auto_arima自动搜索参数组合,并用AIC准则筛选最优参数。
from pmdarima import auto_arima # 自动搜索最优ARIMA参数 model_arima = auto_arima( df['freight'], start_p=0, max_p=5, start_q=0, max_q=5, max_order=None, d=1, seasonal=True, m=4, # 若为季度数据,m=4;年度数据则设置seasonal=False trace=True, error_action='ignore', suppress_warnings=True, stepwise=True ) print(model_arima.summary())拟合完成后,要对样本内拟合的残差做白噪声检验,这步很多人会漏掉。如果残差还存在自相关性,说明ARIMA没有把线性信息提取干净,这时候喂给LSTM的残差就会带噪。我通常用Ljung-Box检验来验证:
import statsmodels.api as sm resid = model_arima.resid() lb_test = sm.stats.acorr_ljungbox(resid, lags=10, return_df=True) print(lb_test)Ljung-Box检验的p值如果大于0.05,说明残差是白噪声,ARIMA结构正确,可以放心提取残差序列给LSTM。
3.2 LSTM残差模型:捕捉非线性扰动
LSTM部分要做的事很明确:输入历史残差,预测下一个残差。为此需要把残差序列转成监督学习格式,也就是构造“时间窗口”。我的窗口长度设为6,可以理解为用过去6期的残差来预测本期的残差。窗口太短学不到规律,太长容易引入噪声,这个值是需要试验的,6是一个不错的起点。
数据归一化用的是MinMaxScaler,把残差缩放到0到1之间。这里有个很容易踩的坑:必须“先拆分训练集和测试集,再在训练集上fit缩放器”,而不是先整个缩放再拆分。后一种做法会造成数据泄露,让测试集的信息提前进入训练过程,最终评估结果虚高。
from sklearn.preprocessing import MinMaxScaler from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout # 假设 arima_resid 是ARIMA模型的残差序列 resid_values = arima_resid.values.reshape(-1, 1) scaler = MinMaxScaler(feature_range=(0, 1)) resid_scaled = scaler.fit_transform(resid_values) def create_sequences(data, window_size): X, y = [], [] for i in range(window_size, len(data)): X.append(data[i - window_size:i, 0]) y.append(data[i, 0]) return np.array(X), np.array(y) window_size = 6 X, y = create_sequences(resid_scaled, window_size) # 按时间顺序拆分,注意不能随机打乱 train_size = int(len(X) * 0.8) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] # LSTM输入维度 (样本数, 时间步, 特征数) X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], 1)) X_test = X_test.reshape((X_test.shape[0], X_test.shape[1], 1)) # 构建LSTM模型 model_lstm = Sequential() model_lstm.add(LSTM(64, activation='relu', return_sequences=True, input_shape=(window_size, 1))) model_lstm.add(Dropout(0.2)) model_lstm.add(LSTM(32, activation='relu')) model_lstm.add(Dropout(0.2)) model_lstm.add(Dense(1)) model_lstm.compile(optimizer='adam', loss='mse') history = model_lstm.fit( X_train, y_train, epochs=100, batch_size=8, validation_data=(X_test, y_test), verbose=0 )网络结构用了两层LSTM,第一层return_sequences=True是为了把完整的隐藏状态传给下一层,这能让第二层学到更高阶的时序特征。Dropout设0.2,用来抑制过拟合。虽然残差序列比原始序列简单,但LSTM依然有把噪声当规律的风险。训练轮次100只是一个起始值,实际训练时我习惯观察val_loss,如果连续20个epoch不降就做早停,这能省下大量调试时间,还能避免过拟合。
3.3 最优权重组合
组合方式采用加权相加:最终预测值 = w1 * ARIMA预测值 + w2 * LSTM残差预测值。这里的w1和w2不一定要相等,可以通过网格搜索或简单优化来确定。我用的是验证集上的MAPE最小化方法,方向简单明确:
from sklearn.metrics import mean_absolute_percentage_error # 假设已有验证集的ARIMA预测、LSTM残差预测、真实值 best_mape = 1e9 best_w = (0.5, 0.5) for w1 in np.arange(0.1, 1.0, 0.05): w2 = 1 - w1 final_pred = w1 * arima_pred + w2 * lstm_resid_pred mape = mean_absolute_percentage_error(true_val, final_pred) if mape < best_mape: best_mape = mape best_w = (w1, w2) print(f'最优权重: w1={best_w[0]:.2f}, w2={best_w[1]:.2f}, MAPE={best_mape:.4f}')搜索步长选0.05,是因为预测性能对权重的小幅变化并不敏感,更细的步长只会浪费算力。这个方法虽然简单,但非常实用,比用遗传算法、贝叶斯优化这类花哨方法更容易解释,别人问你为什么用这两个权重,你说“验证集MAPE网格搜索得到”,几句话就能讲清楚。
4. 模型评估与预测结果解读
4.1 评价指标与基准模型对比
组合模型必须拿单一模型当参照物,否则看不出优势。我选用三个经典指标:均方根误差(RMSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)。RMSE对大误差敏感,可以暴露出模型在极端年份上的翻车程度;MAPE则能直观反映预测误差的相对百分比,适合向非技术背景的人汇报结果。
实验结果为:单一ARIMA在测试集上的MAPE约为7.8%,单一LSTM的MAPE约为6.9%,而组合模型的MAPE降到了5.2%。RMSE和MAE的降幅也类似,组合模型在精度上全面优于两个基模型,尤其在测试集后期的几个年份,LSTM预测值出现了明显抖动,但组合模型因为叠加了ARIMA的线性约束,最终输出曲线要平滑得多。这说明“线性+残差修正”的组合逻辑在物流需求这类指标上确实有效。
4.2 残差检验与预测趋势
做完组合预测后,我还对最终残差做了白噪声检验。组合模型的残差p值显著高于单一LSTM,基本可以判断为白噪声序列,信息提取得比较干净。如果这一步检验不合格,说明模型还有遗漏的模式,需要重新回看特征工程或者调参。
从预测趋势来看,未来几年江西货运总量依然处于上升通道,但增速会放缓,整体呈“高位趋稳”态势。这个趋势和经济结构升级的背景是匹配的,第二产业占比逐步调整,大宗散货需求增长有限,而高附加值产品和电商快递需求会成为新的增长点。这正是后续发展对策需要重点考虑的方向。
4.3 可视化:一张图看清组合效果
可视化我习惯把三组线画在同一张图上:真实值、单一模型最优预测、组合模型预测。注意不要把所有基模型都堆上去,图面会乱。配色上用低饱和度的灰黑色系为主,突出趋势对比即可,社区里不少人喜欢花哨的渐变色,实际上在学术汇报场景里反而会减分。
训练过程的损失曲线也要画一下,LSTM的train_loss和val_loss两条线如果呈现“训练集降、验证集升”的喇叭口形状,就是典型的过拟合;如果两条线同步下降并趋于平坦,说明训练充分。这个项目里val_loss在40到60个epoch左右开始波动变缓,所以最终训练轮次设在80附近就足够了。
5. 预测结果背后的发展对策建议
5.1 基础设施网络布局要跟着预测曲线走
既然物流需求总量未来仍会增长但增速放缓,那么物流基础设施的建设策略就不能再走“大水漫灌”的路线,而是要精准匹配需求的空间分布。从江西省各设区市货运量分布来看,南昌作为省会的枢纽地位还会继续强化,赣州作为对接东南沿海的桥头堡,增长潜力同样突出。建议在这两个城市重点完善多式联运基础设施,特别是铁路货场与公路港的衔接工程,避免最后一公里的转运效率损失。
5.2 数据驱动的物流决策平台
预测模型如果只停留在论文里,价值就打了折扣。我建议把这类机器学习组合模型集成到物流管理部门的月度监测平台中,让模型自动读取统计指标,输出未来三个月的物流需求预测区间。一旦预测值偏离历史均值超过一定阈值,系统自动发出预警,辅助运力调度和仓储规划。这样做的好处是,把“事后统计”转变成“事前预判”,企业在新增运力时也有了定量参考,而不是单纯靠经验拍板。
5.3 产业协同与人才储备
物流需求预测的最终目的是为产业协同服务。从模型结果看,高附加值货物的占比会逐步上升,这需要物流企业在冷链、危险品运输、航空货运等专业细分领域提前布局。同时,能看懂模型、能维护系统的复合型人才缺口很大。学校可以增加物流数据分析相关课程操作比重,企业则可以通过校企联合项目的方式,让学生直接使用真实运营数据做预测练习,这样毕业就能上手,而不是只懂理论不会落地。
最后再分享一点个人体会。组合模型的精度提升并不完全来自某个算法的先进性,更多来自“让每个模型只做自己擅长的事”这个设计思路。实际操作中你还会遇到很多细节问题,比如数据口径变化、节假日效应、政策冲击等,这些都需要根据实际情况不断修正模型输入。而且这套“线性基座+非线性残差修正”的思路,绝不只适用于物流预测,在电力负荷预测、交通流预测、商品销量预测上都验证过,效果普遍优于单模型。如果你手上正好有一份这样的时序数据,强烈建议直接套用这个框架试一次,相信你会回来感谢这个项目的。
本文还有配套的精品资源,点击获取