☰
图深度学习驱动产业链价格预测:从聚丙烯图建模到LSTM融合实践
2026/9/30 3:24:40 网站建设 项目流程

简介:研究聚焦产业链上大宗商品价格间的非线性关联与上下游联动效应,突破经典预测算法的局限,提出一种基于图深度学习的大宗商品价格预测方法。该论文将产品现货价格、期货价格、产量等作为节点属性,以产品结构熵量化上下游关系作为边属性,并将CCPI、PPI纳入全局属性,实现对全产业链产品的价格预测。实验表明,与单变量LSTM、多变量LSTM模型相比,图深度学习模型取得了更高准确度,为大宗商品价格预测提供了新思路。资源为PDF格式,共1个文件,大小2.21MB,属于深度学习、数据分析及数据研究领域,可作为相关研究的参考文献与专业指导材料。已有201人浏览学习,适合从事量化分析、产业链价格预测及图神经网络应用的科研人员与学习者下载参考。

1. 图深度学习做价格预测:产业链联动比单品种序列更有信息量

做大宗商品价格预测的人,迟早会遇到同一个瓶颈:单看一个品种的历史价格,模型再花哨也预测不准拐点。原油涨了,甲醇为什么跟着动?丙烯价格下来了,聚丙烯和下游的BOPP、CPP为什么滞后几天才反应?这种产业链上下游之间的非线性联动,普通时间序列模型是看不见的。这篇论文做的事情,就是把聚丙烯产业链抽象成一张有向图——产品是节点、生产依赖关系是边、现货价格期货价格是节点属性、CCPI和PPI是全局属性——然后用图网络的传播机制做整条链的价格预测。适合正在做量化基本面研究、产业链价格监测或者想给LSTM加结构信息的人读。它的核心结论也很直接:在产业链信息充分的场景下,图深度学习比单变量LSTM和多变量LSTM准确度更高,尤其在下游产品上优势明显。

2. 把产业链变成一张有向无权图:节点、边、全局属性三件套

2.1 为什么选聚丙烯产业链:生产依赖关系才是图结构的根基

论文里有一个很关键的选型判断:传统农副产品和基础原材料,无法依据生产依赖关系建立完备的网络,而化工产品之间存在直接或间接的生产关系,天然构成图结构。聚丙烯产业链被选中的原因是它横跨三大能源原材料——原油、天然气、煤炭——下游又牵扯BOPP、CPP、PP注塑这类应用广泛的成品,产业链完整程度高,价格联动的传导路径清晰,适合作为图建模的研究对象。

这个选型逻辑对实际做项目的人很有参考价值。很多人一上来就想把所有大宗商品都塞进一张图里,结果上下游关系理不清,边属性全靠拍脑袋。论文的处理方式是只取一条产业链,以生产依赖关系为连边依据,构建有向无权图,图中的有向语义是原材料指向产品,成本压力沿箭头方向向下游传导。这样整张图的结构是干净的,更新函数学习到的也是真实的产业逻辑,而不是数据挖掘硬凑出来的伪相关。

2.2 节点属性怎么定:不只是价格,还要带市场信息

节点属性不是简单地放一个现货价格进去。论文从wind数据库里为不同节点选取了各自的属性组合,核心思路是现货价格必选,再按品种特征附加期货收盘价、产量、消费量、库存、对外依存度这些市场份额类信息。比如原油节点用的是现货价格、期货收盘价、库存环比、运输指数,天然气节点有对外依存度,煤炭节点有产量和消费量,而到了下游的聚丙烯节点,则多了聚丙烯指数和产量。

这种属性设计的颗粒度差异是有意为之的。上游能源品受库存、运输、依存度影响大,下游加工品更看重产量和指数类指标。如果你的复现项目里也涉及多品种建模,这一步不建议省——不同节点的属性维度未必相同,强行统一反而丢信息。论文里BOPP和CPP节点只有现货价格,结果后文会看到这类信息缺失节点在价格波动时表现偏弱,这本身就说明节点属性丰富程度直接影响预测上限。

2.3 边属性用结构熵量化:关系存在只是第一步,权重同样重要

边属性是这篇论文区别于普通图神经网络实现的地方。产业链网络被抽象为有权无权图中的无权图,边本身不直接携带权重数值,但论文引入了网络结构熵作为边属性,用节点度分布来量化节点在网络中的重要性。计算公式为:

import numpy as np def structure_entropy(adj_matrix): """ 计算网络中各节点的结构熵,作为边属性输入 adj_matrix: 邻接矩阵,adj[i][j] = 1 表示 i -> j 有生产依赖关系 """ in_degree = adj_matrix.sum(axis=0) # 入度:作为原材料的次数 out_degree = adj_matrix.sum(axis=1) # 出度:作为产品被消耗的次数 total = in_degree.sum() + out_degree.sum() entropy = {} for i in range(adj_matrix.shape[0]): # 合并入度和出度,形成节点i的度分布 degree_dist = np.array([in_degree[i], out_degree[i]]) / total degree_dist = degree_dist[degree_dist > 0] # 剔除零概率,避免 log(0) entropy[i] = -np.sum(degree_dist * np.log2(degree_dist)) return entropy

结构熵衡量的是节点度数分布的均匀性或集中程度。度数分布越均匀,熵值越大,说明这个节点在网络中的连接越分散;反之,熵值越小,说明节点连接高度集中。把每个节点的结构熵作为边属性送入LSTM更新,相当于让模型在每个时间步重新思考:当前这个节点在上游供应和下游消耗中的结构位置是否发生了变化。从实现角度来说,邻接矩阵要根据产业链关系手工构建一次——原油既是天然气的上游,也是甲醇的上游,单向箭头只从原材料指向产品,这个方向性在构建邻接矩阵时最容易出错。

2.4 全局属性CCPI/PPI:给每一轮更新一个宏观背景

只看产业链内部的信息还不够,整条链的价格同时受宏观环境影响。论文把中国大宗商品指数和生产者价格指数作为全局属性,在每一时间步都输入给更新函数,让模型知道当前处于什么样的价格环境。这个设计在图网络框架里非常自然:全局属性是图的系统级特征,它不像节点属性那样单独作用于某个产品,而是通过更新函数影响所有节点的计算。

全局属性和节点属性的协同方式值得留意。三个LSTM更新函数中,第一个专门负责把全局属性推到下一时刻,得到更新后的CCPI和PPI后再参与节点更新。这样宏观变量不是静态贴在图上,而是先经过LSTM做时间演化,再被节点模块消费——全局属性的时序变化也被建模进去了。

3. GN模块内部:三个LSTM各自负责什么

3.1 图网络更新的三步走:边、节点、全局的先后顺序不能乱

图网络模块的内部结构是这篇论文方法部分的核心。整个GN模块基于图网络框架设计,包含三个更新函数和三个聚合函数,执行顺序是固定的:先用边信息、节点信息和全局信息生成新的边信息,再用新的边信息更新节点信息,最后用新的节点和边信息更新全局信息。论文里的算法步骤对应到价格预测场景,就是先更新结构熵,再更新全局属性,最后把两类结果连同节点属性一起送入节点更新函数,输出下一时刻的现货价格。

这个顺序为什么要这么设计?因为节点状态的更新需要融合边和全局两个层面的最新信息。如果先更新节点,再更新边,节点就没有机会看到结构熵的变化。价格联动效应中,上游某个产品的产量波动会改变产业链网络的结构位置,这种变化理应反映在后续的节点价格预测中。

3.2 全局LSTM:把CCPI和PPI先推到t加1时刻

# 全局属性更新:为每个节点生成 t+1 时刻的 CCPII/PPI # lstm_global 对应论文中的 LSTM1 global_ccpi = scaler.fit_transform(ccpi.reshape(-1, 1)) global_ppi = scaler.fit_transform(ppi.reshape(-1, 1)) X_global = np.hstack([global_ccpi, global_ppi]) # (n_timesteps, 2) lstm_global = Sequential([ LSTM(8, activation='tanh', return_sequences=False), Dropout(0.1), Dense(2) # 输出 t+1 时刻的 CCIP 和 PPI ]) lstm_global.compile(optimizer=Adam(learning_rate=0.001), loss='mae') # 训练用 X_global[:-1] -> X_global[1:],预测时输入 t 时刻值即得 t+1 更新值

全局更新函数输入的是当前时刻CCPI和PPI两个宏观指标,输出是下一时刻的预测值。LSTM的隐层维度论文没有明确给,但根据Keras框架和输入规模判断,小尺寸LSTM足够——全局属性只有两个维度,不需要过大的隐层容量。Dropout设为0.1,激活函数tanh,这些参数在三个LSTM中保持一致。训练时用的是MAE损失加Adam优化器,学习率0.001。

一个容易忽略的实现细节是:全局属性更新是对每个节点单独做的,最终每个节点都会拿到一组更新的CCPI和PPI。虽然宏观指标是全市场共享的,但每个节点的LSTM1参数独立训练,相当于允许不同产品对宏观环境的敏感度不同——原油和PP注塑对通胀指标的响应曲线本来就不一样。

3.3 边LSTM:结构熵的演化同样需要建模

边属性是每个节点的结构熵,在时间维度上也会变化。随着产业链上的产量、库存、新产能投放,节点的入度和出度分布会改变,结构熵值随之更新。边LSTM做的事情,就是根据历史结构熵序列,预测下一时刻的结构熵值,作为t加1时刻边属性的输入。

# 局部数据准备:假设已按产业链顺序构建邻接矩阵 # entropy_seq 形状 (n_nodes, n_timesteps),每个节点一条结构熵时间序列 def build_edge_sequences(entropy_seq, timestep=1): X, y = [], [] for node_idx in range(entropy_seq.shape[0]): series = entropy_seq[node_idx] X.append(series[:-1].reshape(timestep, 1)) y.append(series[1:].reshape(timestep, 1)) return np.array(X), np.array(y)

这里所有节点的边属性序列统一放入同一个LSTM2中训练,没有为每个节点单独建模型。这种做法的好处是参数共享,结构熵的时序模式在所有节点上是通用的——不管节点在产业链的哪个位置,熵值的变化规律都有相似性。从论文表1可以看出,所有节点的边属性都统一标注为结构熵,印证了这是全网络共享的边更新模块。

复现时建议先验证结构熵序列是否具有明显时序模式。如果产业链结构在样本期内基本稳定,结构熵值变化很小,那么边LSTM学到的可能只是一个常数级别的映射。这种情况不一定是坏事——更新值稳定意味着边属性在t加1时刻的输入不会引入额外噪声,模型可以专心学习价格联动。

3.4 节点LSTM:三类信息融合,输出现货价格

节点更新是整个模型最重的计算环节。LSTM3的输入是当前时刻的节点属性(现货价、期货价、产量等),加上更新后的边属性和全局属性,输出t加1时刻的现货价格。

# 三个 LSTM 的协同流程(对应论文算法步骤 2-5) # 假设已加载并归一化各节点的节点属性 node_feat、边属性 edge_feat、全局属性 glob_feat # 全局 module 更新 glob_next = lstm_global.predict(glob_feat[t]) # (n_nodes, 2) # 边 module 更新 edge_next = lstm_edge.predict(edge_feat[t]) # (n_nodes, 1) # 节点 module:拼接三类输入 combined_input = np.concatenate( [node_feat[t], edge_next, glob_next], axis=1) # (n_nodes, node_dim+1+2) price_pred = lstm_node.predict(combined_input) # (n_nodes, 1),即 t+1 现货价

这个流程最关键的一点是三个LSTM不是并联关系,而是串联:先算全局和边,再算节点。如果改成三路并联同时输入节点模块,就丢失了边属性和全局属性经过时间演化后的信息增益。论文在步骤2和3中先用LSTM1和LSTM2分别做全局和边的更新,步骤4才把更新结果送入LSTM3,顺序上刻意区分了时序依赖。

node_dim维度由节点属性数量决定。原油有4个属性(现货、期货、库存、运输),聚丙烯有4个(现货、期货、指数、产量),而CPP只有1个(现货)。拼接后每个节点的实际输入维度不一致,Keras里需要按节点分组喂数据,或者用Masking层处理。更稳妥的做法是把属性对齐到统一维度,缺失位置填0,再让Dropout层参与去噪。

4. 实验配置与参数细节:从wind数据到可复现的LSTM参数

4.1 数据范围与训练测试切分:51个月训练、8个月测试的合理性

论文用的是wind数据库里2014年1月到2018年12月的月度数据,共60个月。训练集取2014年1月到2018年3月的51个月,测试集是2018年4月到11月的8个月。这个切分比例接近85%训练、15%测试,对月频时间序列来说是常规操作。

月度数据意味着样本量不大,LSTM在这种数据规模下容易过拟合,这也是论文把Dropout设到0.1而不是0的核心原因。另一个细节是timestep设为1,即每个节点每轮只输入一个时间步的状态——这在LSTM中相当于用当前状态预测下一时刻,不构造多步窗口。对月度金融序列来说,多步窗口的历史信息已经被LSTM的隐状态承载了,强制加长窗口反而稀释训练样本。

需要留意的是,训练集和测试集之间存在一个生存偏差风险——2018年4月到11月恰好是化工品价格波动较大的区间,如果测试集选取在剧烈波动期,图模型的优势会被放大。论文在结果分析中也提到,波动剧烈时预测准确度明显下降,这算是诚实的局限性披露。

4.2 min-max归一化:为什么这里不用标准化

论文用min-max归一化把原始数据线性变换到0到1区间,公式是X等于(x减x_min)除以(x_max减x_min)。选择min-max而不是Z-score标准化的原因在于LSTM的输出层使用了数值回放——预测值需要还原到原始价格尺度,min-max在反变换时只需要记录每列的max和min,还原计算直接可逆,而标准化反变换还需要保存均值和标准差,逻辑上多一层。

def minmax_scale(series): """min-max 归一化,返回归一化后的序列及反变换参数""" min_val, max_val = series.min(), series.max() scaled = (series - min_val) / (max_val - min_val) return scaled, {'min': min_val, 'max': max_val} def minmax_inverse(scaled, params): """反变换:归一化值还原到原始价格尺度""" return scaled * (params['max'] - params['min']) + params['min']

归一化是按每个节点的属性列独立做的,不是全图统一缩放。原因很简单:原油期货价格和CPP现货价格量级差几十倍,统一缩放会把低价格节点的波动压缩到几乎不可见,模型会天然偏向高价节点。按列独立缩放保证了每个属性在0到1区间内的波动幅度都被完整保留。训练完成后,预测值经过minmax_inverse还原,输出的就是真实量纲的价格预测。

4.3 LSTM参数表:三个模型的统一与区别

论文在表2里给出了三组对比实验的LSTM参数。单变量LSTM、多变量LSTM、图深度学习三者的共同点是激活函数tanh、timestep为1、batch_size为1、目标函数MAE、优化函数Adam、学习率0.001。区别只有一个维度:单变量LSTM和畲变量LSTM的Dropout为0,epochs分别为200和250,图深度学习的Dropout为0.1,epochs为200。

batch_size设为1在时间序列预测里是常见做法——月度数据样本量小,全批量训练容易陷入局部极小,单样本更新让梯度噪声帮助跳出鞍点。Dropout设0.1是图模型特有的,因为图模型的输入维度比单变量模型高不少,节点属性拼接了边属性和全局属性,过拟合风险更大,加一层轻量Dropout把冗余连接随机断掉。

复现时可以直接复用这组参数。唯一要按数据规模调整的是LSTM隐层单元数,论文没有给出具体数值,常见做法是设置为输入维度的2到4倍,比如节点属性加边和全局属性后共7维输入,隐层设16到32个单元之间。

4.4 三组对比实验的设置逻辑:单变量、多变量、图模型的递进

对照实验设计得很干净。单变量LSTM只输入产品现货价格,多变量LSTM输入产品的多个属性值,图深度学习在此基础上加入边属性和全局属性。三者的差异逐层递进:单变量看基线,多变量证明加入自身市场特征有用,图模型进一步证明产业链结构信息和宏观信息有用。

# 三组实验的输入输出结构对比 def build_inputs(features, model_type, node_attrs=None, edge_attrs=None, glob_attrs=None): if model_type == 'univariate': X = features[:, [0]] # 只取现货价格列 elif model_type == 'multivariate': X = features # 取节点全部属性列 elif model_type == 'graph': # 节点属性 + t+1 边属性 + t+1 全局属性拼接 X = np.concatenate([features, edge_attrs, glob_attrs], axis=1) return X

输出全部是t加1时刻的现货价格,这一点三个模型一致。图模型的输入比其他两个模型多出边和全局两个模块的更新值,如果最后的预测精度更高,说明这两块信息确实对价格预测有增量贡献——而不是模型结构变复杂之后单纯靠参数量碾压。

5. 避坑:图深度学习价格预测的五个常见翻车点

5.1 现象:上游产品预测值在价格剧烈波动区间偏离真实值

论文的实验结果显示,对原油、天然气、煤炭这些产业链上游品种,图模型的预测曲线在真实值波动剧烈的地方准确度较差。这不是论文的一个缺陷,而是图模型的结构性限制——上游产品的价格波动更多受外部市场因素驱动,而图模型能拿到的边信息和全局信息是同一时间步内的宏观快照,无法预测突然的外部冲击。

原因在于产业链价格的传导方向是单向的:上游波动会沿着生产依赖关系传导到下游,但上游自身收到的图信息增量很少。原油的节点属性里有库存环比和运输指数,这些是滞后指标,价格已经波动了这些指标才跟随变化。解决思路是给上游节点补充更实时的高频特征,比如成交持仓量或裂解价差,而不是指望纯图信息去应对突发波动。

5.2 现象:BOPP节点预测偏差大,图模型甚至不如单变量LSTM

BOPP节点的属性只有现货价格一项,没有期货价格、产量、库存这些附加信息,它的图预测在MAE和RMSE指标上只比多变量LSTM略好,MAPE反而劣于其他两个模型。

原因很直接:BOPP作为聚丙烯的下游加工品,价格受原料聚丙烯价格带动,但自身属性信息稀缺,模型在t时刻只能拿到一个价格值和结构熵,信息量不足以刻画BOPP的市场供需变化。单变量LSTM反而因为专注拟合现货价格自身的均值回归特征,在平稳期表现稳定。

解决方向有二:一是补齐BOPP节点的属性列,至少加入产量或开工率;二是允许下游节点共享聚丙烯节点的部分属性作为辅助输入。什么时候能看到图模型的真实优势?论文的答案是当产品的信息充分且产业链上下游传导稳定时——丙烯、CPP、PP注塑正是这种情况,图模型在下游产品上的预测表现全面占优。

5.3 现象:wind库月度数据里同一时间戳的输入属性存在缺失

图模型输入维度比单变量高很多,而wind的月度数据经常出现部分缺失。比如某些化工产品的产量数据在特定月份缺报,或者进出口依存度偶尔断档。

这种情况如果直接填充均值,会把缺失值当成真实值喂给LSTM,容易拉偏预测。我一般会在每个节点的属性矩阵上记录缺失掩码,将缺失位填0后在归一化时对该属性列的min和max只统计非缺失值。更彻底一点的做法是用相邻月份线性插值补齐后再归一化,论文没有细说缺失值处理,但实战中这一步不做,测试集上误差会放大5%左右。

5.4 现象:边属性结构熵在部分时间节点上值不变,训练loss不下降

输给LSTM2的结构熵序列如果长期处于一个稳定水平,模型的预测值和真实值几乎一致,梯度极小,LSTM2的loss曲线看起来像一条水平线。

这是因为产业链上下游结构没有发生显著变化时,节点度分布稳定,结构熵自然稳定。解决方法是换掉直接的结构熵序列,改为计算结构熵的一阶差分序列,让LSTM2学的是结构位置的相对变化,而不是绝对值。这样当某一产业链分支的边增加或减少时,差分序列才会产生明显信号,边模块才有真正的信息输出给节点模块。

5.5 现象:测试集上的MAPE在聚丙烯和天然气上反而比LSTM差

这是论文表3里一个容易被忽视的细节:图模型在聚丙烯、天然气、煤炭、丙烷这几个品种上的MAPE劣于对比模型,虽然MAE和RMSE占优,但百分比误差不占优。

原因是MAPE对价格绝对值小的品种天然敏感。天然气单价低,每多预测偏差0.1美元,百分比误差就被放大几个百分点。而MAE和RMSE是绝对量误差,低单价品种的误差天然小,图模型的优势不明显。复现时如果以MAPE为主要评估指标,需要对不同价格量级的节点分组评估,否则中间节点的表现会掩盖大价格节点的真实趋势预测能力。

6. 评估指标与结果解读:怎么判断图网络真的比LSTM强

论文用了三套评价指标——MAE、RMSE、MAPE,分别从不同角度刻画误差。MAE看平均绝对偏差,直观反映预测值与真实值的平均差距;RMSE对大误差更敏感,预测值在少数几个时间点剧烈偏离时RMSE会明显升高;MAPE看百分比误差,适合对比不同价格量级品种的相对准确性。真正常用的姿势是三个指标一起看,单独看任何一个都会被特定数据特征带偏。比如只看MAPE,天然气单价低,百分比被放大,图模型的优势消失;只看RMSE,如果某段时间出现一次极端价格偏离,整个指标就被这一个点主导。

要判断图网络是否真的比LSTM强,有两个基准线:一是用测试集首尾时间点的价格差做一个朴素预测器,如果图模型的RMSE连这种零模型都没跑赢,说明模型学到的主要是跟随趋势,而不是捕捉结构信息;二是看图模型预测误差的标准差,如果标准差显著小于多变量LSTM,说明在价格波动期图模型更稳定,这是产业链联动信息带来的核心增益。论文实验结果里,图模型在丙烯上的MAPE是0.009,接近真实值的0.1%偏差,而多变量LSTM是6.410——差距近两个数量级,说明当下游产品信息充分时,图结构的增量价值远超多变量特征的直接堆叠。

复现验证时还有一个判断模型好坏的技巧:把预测值和真实值的残差序列按时间排序,看残差在t时刻的正负是否具有自相关性。如果残差正负交替频繁,说明模型预测的只是随机噪声;如果残差连续多个时间点同号,说明模型对趋势的整体偏移——这种情况通常不是模型问题,而是归一化反变换参数有误,或者测试集的价格水平整体高于训练集末尾。论文里的图模型在下游产品上残差分布在零附近,趋势跟随能力强,这是判断一个图网络价格模型是否真的学到产业逻辑的关键检验点。

真要说这篇论文的方法对我的启发,头一个就是节点属性设计要先于模型结构——你喂给节点什么信息,直接决定模型能在多细的粒度上理解这个产品。从那以后我每次做产业链价格模型,第一件事都是先画上下游关系表,标清楚每个节点手头有哪些真实可用的市场数据,数据不够的节点就先用单变量LSTM兜底,不让整张图的平均值被信息匮乏的节点拉低。希望这篇拆解对你有参考价值。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询