ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

相关性分析+CNN-Attention-LSTM期货预测模型源码拆解与避坑指南

相关性分析+CNN-Attention-LSTM期货预测模型源码拆解与避坑指南 简介面向计算机相关专业学生的毕业设计或项目实战这套基于相关性分析的CNN-Attention-LSTM期货价格预测方案将卷积特征提取、注意力机制与长短期记忆网络结合用于捕捉金融时序数据中的空间特征与长期依赖。压缩包共29个文件大小约30.28MB涵盖8个Python源码、6个npy数组、3个Excel数据表、2个TensorFlow模型checkpoint及2个PDF使用教程等从相关性分析、时间步处理到模型预测和API封装均包含配套脚本与说明。已有81人学习该资源。对准备毕设或课程设计的学生而言不仅可参考完整的前后端预测流程还能直接利用附带的玉米期货数据集、SQL数据表、训练权重与热力图结果进行复现调试是一份能帮助快速理解混合深度学习模型在真实金融场景中应用的实操性资料。1. 用相关性分析给 CNN-Attention-LSTM 期货预测模型灌数据这份毕设源码包到底值不值得跑期货价格预测这种时序建模任务网上能找到的 Python 源码不少但多数要么只给模型不给数据要么给了模型和训练脚本却把最耗时间的数据预处理、相关性筛选和 checkpoint 恢复逻辑压在一句“详见代码”里。这份基于相关性分析的 CNN-Attention-LSTM 项目不一样它是把毕业设计的完整链条都留下来了从原始玉米期货周报数据、SQL 和 Excel 表到相关性分析脚本、时间步处理脚本、模型定义、训练脚本、预测脚本再到 Web 前端配置教程和已经训好的 .ckpt 权重全部在压缩包里。也就是说你不用自己攒数据也不用从零复现模型结构下载解压、装好依赖就能把一条预测链路从特征筛选跑到结果可视化。它的核心思路是先用相关性分析找出哪些输入特征真的对期货价格有影响再把这些特征按时间窗口切成样本喂给 CNN 提局部特征、Attention 加权关键信息、LSTM 建模长期依赖。很适合正在做毕设或课程设计的计算机、数据分析专业学生也适合想参考完整项目结构的人。但前提是你得先把数据处理和训练脚本里的几个隐藏约定搞清楚否则很容易出现“模型代码没问题结果却离谱”的情况。这篇文章就按我拆包时的顺序把数据、模型、训练和预测这几块逐个过一遍踩过的坑也都标出来。2. 相关性分析选特征为什么先算相关性以及这份包里用什么数据算2.1 为什么不能把全部字段直接喂给模型刚拿到这份包的时候我下意识想看一眼模型输入维度结果发现 train_x.npy 的最后一维并不是原始 Excel 表里的列数。也就是说作者是先做了特征筛选才构建的训练数据。这一步很有必要期货价格除了开高低收和成交量还会受持仓量、仓差、外盘相关品种、宏观指标等因素影响。字段一股脑全塞进去CNN 和 Attention 不是不能学但噪声特征会稀释真正有用的信息而且训练轮次一多模型容易把无关字段的偶然相关性也记进去泛化能力反而变差。相关性分析的作用就是事先把“和预测目标关系不显著”的字段筛掉。常见做法是对每个候选特征计算与目标变量的相关性系数设定一个阈值低于阈值的直接丢弃。这个过程的性价比非常高数据的列数降下来了训练速度变快模型稳定性也更好代价只是多跑几十行脚本。项目里专门放了一个“相关性分析.py”还附带“相关性分析用表.xlsx”和“相关性分析数据.npy”说明作者是把这一步当成独立的预处理环节来维护的。2.2 Pearson 与 Spearman 两种相关性系数怎么选相关性系数不是只有一种。Pearson 系数衡量的是线性相关性公式上是协方差除以标准差乘积它对离群点和非线性关系比较敏感Spearman 系数则是把数据转成秩次后再算衡量的是单调相关性对离群值和偏态分布更稳健。价格类数据在极端行情下容易出现尖峰和厚尾直接上 Pearson 很容易被少数几天的大涨大跌带偏。搜索热词里也能看到很多人关注 spearman 相关性分析这个方向是对的。所以我一般会建议先对每个特征画一下分布或者直接跑一个 Spearman 相关性矩阵看看和收盘价或下一期收益率的相关系数。若某个特征与目标的 Spearman 系数绝对值高于 0.2 到 0.3保留下来才有意义如果连单调关系都不明显后面喂进 LSTM 基本就是噪声。项目里的“玉米期货数据周报7.25.xlsx”字段有限你在自己替换数据时注意按这个逻辑重新算一遍阈值不要沿用别人写死的字段。下面是这个包里相关性分析脚本的典型逻辑核心是读取多列数据、算相关系数矩阵、画热力图并输出筛选后的特征列名import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt # 读取按行存储的期货周报数据date_col 是日期target_col 是预测目标 df pd.read_excel(玉米期货数据周报7.25.xlsx, engineopenpyxl) feature_cols [开盘价, 最高价, 最低价, 收盘价, 成交量, 持仓量, 仓差] target_col 下一周收盘价 # 做时间平移构造目标列上一行特征对应当前行目标 df[target_col] df[收盘价].shift(-1) df df.dropna().reset_index(dropTrue) # 计算 Spearman 相关性矩阵排序输出每个特征与目标的系数 corr_matrix df[feature_cols [target_col]].corr(methodspearman) target_corr corr_matrix[target_col].drop(target_col).sort_values(keylambda x: abs(x), ascendingFalse) print(与目标变量的 Spearman 相关系数) print(target_corr) # 画出特征间相关性的热力图用于观察特征是否冗余 plt.figure(figsize(10, 8)) sns.heatmap(corr_matrix, annotTrue, cmapRdBu_r, fmt.2f) plt.title(Feature Correlation Heatmap) plt.savefig(相关性热力图.png, dpi300, bbox_inchestight) plt.show() # 按阈值筛选特征并把结果保存成列表供后续时间步处理脚本使用 selected_features target_corr[abs(target_corr) 0.2].index.tolist() print(筛选后保留的特征, selected_features)这段代码的逻辑分三步第一步先读取 Excel把“下一周收盘价”作为预测目标做 shift(-1) 时间平移第二步用 pandas 自带的 corr 方法算 Spearman 系数按绝对值排序第三步用阈值筛选特征同时保存一张热力图方便在论文里当结果展示图用。参数上需要注意两个地方shift 的符号决定了预测方向和目标构造方式shift(-1) 表示用本周特征预测下周价格阈值 0.2 不是固定值改成 0.3 会筛得更狠0.1 则保留更多特征。看这张热力图时除了关注特征与目标的相关系数还要看特征之间是否高度相关比如开盘价和收盘价通常相关性极高同时保留会造成多重共线性LSTM 虽然不太怕这个但会让 Attention 的权重分配变得不稳定。项目里的“我是热力图.png”就是这一步产出的结果图你可以在复现时对比自己生成的热力图确认特征间相关结构一致。3. 时间步处理与数据集构建滑动窗口怎么设三者维度如何对齐3.1 把截面数据变成时间序列样本相关性分析筛选出特征后数据还是一个按时间排序的二维表格行是时间点列是特征。CNN 和 LSTM 吃的都是三维张量形状是 (样本数, 时间步长, 特征数)所以必须做时间步处理。项目里的“时间步处理.py”干的就是这件事核心概念叫滑动窗口设一个窗口长度 time_steps用连续 time_steps 行的特征作为输入预测窗口之后那个时间点的价格。这里最容易错的是窗口和预测目标的对齐。你要预测的是“下一个时间点”还是“未来第 N 个时间点”决定了标签的取值位置。包里的 train_x.npy 和 train_y.npy 形状应该能直接看出作者选的窗口长度比如 train_x 是 (样本数, 5, 特征数)就说明是用过去 5 周的数据预测下一周。时间步长越小样本数越多但模型能看到的上下文越短时间步长太大数据量不够时容易过拟合。对周线数据5 到 10 是比较常见的选择。3.2 切分数据集时一定要防数据泄漏时间序列切训练集和测试集不能用随机切分必须按时间先后切。如果用 sklearn 的 train_test_split 默认参数随机打乱后测试集里会出现训练集之后的数据等于让模型“偷看”了未来验证结果会虚高到了实盘完全失效。项目里把 train_x、train_y、test_x、test_y 分别存成 .npy 文件从文件名看应该是按时间顺序手动切分的。处理脚本里还要做一个关键操作归一化。价格数据的绝对值从几千到几万不等不归一化直接送进 LSTM梯度容易爆炸。常见做法是用 MinMaxScaler 把数据缩放到 [0,1] 区间但要注意 scaler 只能用训练集的统计量去 fit然后再分别 transform 训练集和测试集。如果把全部数据一起 fit等于又把测试集的信息泄漏进了训练过程。下面是一个可用的时间步处理实现把相关性分析筛出的特征表转换成 (样本数, 时间步长, 特征数) 的 npy 数组import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler def create_sequences(data, time_steps5, target_idx0): 将二维表格数据切成滑窗样本 data: 归一化后的二维数组每行是一个时间点 time_steps: 用多少个历史时间点做预测 target_idx: 目标列在特征矩阵中的列索引 xs, ys [], [] for i in range(len(data) - time_steps): x data[i : i time_steps, :] y data[i time_steps, target_idx] # 预测窗口后的目标值 xs.append(x) ys.append(y) return np.array(xs), np.array(ys) # 读入第 2 步输出的数据 df pd.read_excel(处理后的数据表.xlsx, engineopenpyxl) feature_cols [c for c in df.columns if c not in [日期, 下一周收盘价]] target_col 下一周收盘价 # 先拆时间前 80% 作为训练集后 20% 作为测试集 train_size int(len(df) * 0.8) train_df df.iloc[:train_size].copy() test_df df.iloc[train_size:].copy() # 只对特征做归一化目标列可以单独处理 scaler MinMaxScaler(feature_range(0, 1)) train_scaled scaler.fit_transform(train_df[feature_cols]) test_scaled scaler.transform(test_df[feature_cols]) # 切滑窗并保存 train_x, train_y create_sequences(train_scaled, time_steps5, target_idxfeature_cols.index(target_col)) test_x, test_y create_sequences(test_scaled, time_steps5, target_idxfeature_cols.index(target_col)) np.save(train_x.npy, train_x) np.save(train_y.npy, train_y) np.save(test_x.npy, test_x) np.save(test_y.npy, test_y) print(train_x:, train_x.shape, train_y:, train_y.shape) print(test_x:, test_x.shape, test_y:, test_y.shape)上面这段代码有三个参数值得解释。train_size 控制训练测试切分比例0.8 是一次常见选择但周线数据本来就少如果只有一两百行建议用 walk-forward 验证的方式而不是死板的按比例切一次。target_idx 是目标列在特征矩阵中的位置索引如果目标列被 MinMaxScaler 一起缩放预测出来的也是缩放后的值后面可视化时需要反变换回原始价格。time_steps5 对应 5 周窗口你在改这个参数时train_x 的第三维不变第一维会变成总行数减去窗口数。需要特别提醒一个小细节归一化的目标列最后画出预测曲线时数值都在 [0,1] 区间看起来趋势对但实际价格对不上。我习惯把 target 单独存一份原始值或者在逆变换时把 target 列拼回去再调用 scaler.inverse_transform。项目里的 test_y.npy 看命名应该是目标列但它是归一化前的还是归一化后的需要你加载后打印一下数值范围确认。这一步偷懒的话后面评估 RMSE 时数值会完全失真。4. 模型结构拆解CNN、Attention、LSTM 在预测任务中各干哪一部分活4.1 三个模块的分工与拼接顺序这份项目叫 CNN-Attention-LSTM结构顺序是输入先经过 CNN再经过 Attention最后进 LSTM。这个顺序不是随便排的每个模块解决一个具体问题。CNN 用一维卷积在时间维度上滑动相当于在局部窗口内提取价格波动的短时模式比如连续三周的上涨趋势、放量突破之类的局部形态Attention 层接着对 CNN 输出的特征做加权让模型学会把注意力集中在与预测目标最相关的历史片段上LSTM 最后处理经过筛选和加权后的序列利用门控机制建模长期依赖。有人会问为什么不让 LSTM 直接处理原始序列。如果直接上 LSTM输入序列太长模型容易丢失早期的关键信息而且 LSTM 对局部特征的提取能力不如 CNN 那样“显式”。反过来如果只用 CNN感受野受限无法捕捉长周期依赖。把三者串联等于先把原始序列降维提特征再做重要性筛选最后建模时序依赖三个模块互相弥补短板。4.2 模型代码的可复现要点与参数调整思路项目里的 cnn_attention_lstm.py 定义了完整模型根据包里提供的 checkpoint 文件命名my_modelv1.ckpt、my_modelv2.ckpt作者至少训练过两版权重v1 和 v2。拆包时先看模型输入维度是否与 train_x.npy 的第二维、第三维对齐这是最容易出问题的地方。下面是这种结构最常见的实现方式使用 TensorFlow / Keras 的函数式 APIimport tensorflow as tf from tensorflow.keras.layers import Input, Conv1D, MaxPooling1D, LSTM, Dense, Attention from tensorflow.keras.models import Model def build_cnn_attention_lstm(time_steps5, n_features6, lstm_units64, cnn_filters32): 构建 CNN-Attention-LSTM 复合模型 time_steps: 时间窗口长度 n_features: 特征数量 lstm_units: LSTM 隐藏单元数 cnn_filters: 卷积核数量 inputs Input(shape(time_steps, n_features)) # CNN 模块一维卷积提取局部特征池化降维保留主要信息 x Conv1D(filterscnn_filters, kernel_size3, activationrelu, paddingsame)(inputs) x MaxPooling1D(pool_size2)(x) # Attention 模块对时间步做加权求和 attention_scores Dense(x.shape[1], activationsoftmax, nameattention_scores)(x) x tf.reduce_sum(x * tf.expand_dims(attention_scores, axis-1), axis1) # LSTM 模块处理加权后的序列数据 x LSTM(lstm_units, return_sequencesFalse)(x) x Dense(16, activationrelu)(x) outputs Dense(1)(x) model Model(inputsinputs, outputsoutputs) model.compile(optimizeradam, lossmse, metrics[mae]) return model model build_cnn_attention_lstm( time_steps5, n_featurestrain_x.shape[2], lstm_units64, cnn_filters32, ) model.summary()这段代码有几个细节要注意。第一Attention 的实现方式不是标准的 Bahdanau 或 Luong而是用 Dense softmax 生成每个时间步的权重再和 CNN 输出做加权求和属于一种简化版的自注意力。它够用但如果你想在论文里写“注意力机制”最好把公式和数据维度对齐讲清楚。第二MaxPooling1D 的 pool_size2 会把时间步长从 5 压到 3 或 2导致 Attention 作用的维度变小信息有损耗我拆包时遇到过一个情况窗口设为 5、卷积核为 3池化后序列长度直接变了Attention 维度对不上所以代码里用 x.shape[1] 动态获取池化后的长度。第三LSTM 默认 return_sequencesFalse只输出最后一个时间步的隐藏状态再接全连接层输出价格预测值。超参数上lstm_units64 对周线小样本数据是够用的如果数据量大可以加到 128 或 256。cnn_filters32 是卷积核数量这个值越大能提取的局部特征类型越多但参数量也会上升。kernel_size3 表示卷积核覆盖 3 个时间步。如果你想把预测目标从“下一周价格”改成“未来三周均值”需要改的是数据预处理部分而不是模型结构。5. 避坑与排查训练脚本和 checkpoint 加载的真实坑点5.1 加载 checkpoint 报错模型结构必须与保存时完全一致现象加载 my_modelv1.ckpt 时Keras 报错说权重形状不匹配或者提示缺少某个层。原因TensorFlow 的 checkpoint 是按层名和权重形状保存的。你本地改动了模型结构比如把 LSTM 单元数从 64 改成 128或者把输入的 n_features 从 6 改成 7checkpoint 里的旧权重就没办法映射到新模型上。最隐蔽的情况是你只是改了一下层名比如把变量名从 attention_scores 改成 attention_weights加载时也会对不上。解决要么保持模型定义和原脚本一致直接 reuse 作者留下的模型结构要么把加载模型的代码改成 build_cnn_attention_lstm(...) 和保存时完全一致再用 model.load_weights() 去恢复。实在不匹配的话就别加载旧权重从零训练因为这两个 checkpoint 本身也就是作者的中间产物不是最优结果。5.2 预测结果是一条水平直线现象pred.npy 画出来是一条直线数值基本不变化或者变化幅度小到看不出来。原因最常见的是目标列做了归一化预测值在 [0,1] 区间内原始价格是几千的数值画在同一个坐标轴里看起来就是一马平川。另一种情况是模型严重欠拟合卷积和 LSTM 学到的信息不足直接输出训练集目标均值。如果是前者把预测结果做 inverse_transform 再画图就能看到趋势如果是后者加大训练轮次或者调高 LSTM 单元数。解决打印 pred.npy 的 min 和 max如果范围在 0 到 1 之间说明是归一化后的值用保存过的 scaler 反变换回来如果反变换后仍是一条直线把训练轮数调到原来的两倍并观察 loss 是否还在持续下降。5.3 训练 loss 涨涨跌跌根本降不下去现象train_v2.py 跑起来后loss 曲线像锯齿一样来回震荡几十个 epoch 下来没有明显下降趋势。原因学习率设得太大Adam 优化器在最优解附近来回横跳无法收敛。或者是 LSTM 输入的数值范围差异过大归一化环节没做好。还有可能是 batch size 太小单个 batch 的梯度方向抖动剧烈。解决先把学习率从默认的 0.001 降到 0.0005 或 0.0001观察 loss 是否平滑下降。把数据归一化范围从 [0,1] 改为 [-1,1]有时候对 LSTM 收敛更友好。batch size 如果设的是 16 或 32逐次翻倍看效果。5.4 测试集效果比训练集好这是数据泄漏了现象训练集 loss 很高测试集 loss 反而很低或者测试集预测曲线和真实曲线贴合得过分完美。原因训练测试切分不是按时间顺序而是随机切分测试样本中包含了与训练样本相邻时间点的数据相当于模型已经见过这部分信息的“近似版本”。另一个常见泄漏点是把整个数据集的均值方差用于归一化测试集的分布信息提前混进去了。解决严格按时间顺序先用前 80% 训练再用后 20% 测试训练集和测试集各自用训练集的统计量归一化。这个项目的 npy 文件如果已经切好你在复现时可以先检查 test_x 的时间戳是否全部晚于 train_x。5.5 Web 前端跑不通端口占用和跨域问题现象按照“Web前端配置及使用教程.pdf”启动 pred_API.py浏览器访问时请求失败或者接口一直转圈。原因pred_API.py 里如果用了 Flask默认端口是 5000本地有其他服务占用就会出现端口冲突。前端页面和后端接口不在同一个端口时浏览器会拦截跨域请求。解决先手动到命令行启动 pred_API.py看终端输出是否报端口被占用被占用就换一个端口同时把前端配置里的接口地址改成新端口。跨域问题在 Flask 里加 flask-cors 扩展即可pip install flask-cors 后调用 CORS(app) 就能放开。6. 验证与应用从模型权重跑到预测曲线再到接口化调用的完整串联先把完整的调用链路搞清楚这份资源才算真正跑通。我建议按 train_v2.py → pred.py → pred_API.py 这个顺序走一遍中间不要跳。train_v2.py 负责训练并把权重保存为 my_modelv2.ckptpred.py 加载训练好的模型读取 test_x.npy生成 pred.npy 并画出对比曲线pred_API.py 则把上面这套逻辑封装成 HTTP 接口供 Web 前端调用。接口的输入输出格式直接参考“Web前端配置及使用教程.pdf”用 Flask 的 request.json 接收前端传过来的特征数据返回预测结果。验证模型好坏不要只盯着训练 loss。加载 train_y.npy 和 pred.npy计算 RMSE 和 MAE同时画一张真实值 vs 预测值的折线图肉眼观察滞后性。滞后性太明显说明模型更多是在复刻上一期价格而不是真正学到了趋势这时候调大时间步长或加深 LSTM 有一定帮助。画图时一定要把预测值反归一化回原始价格区间否则曲线斜率看起来都对但 Y 轴标注是 0.4、0.6 这种数值论文里根本没法用。我的个人习惯是拿到任何别人分享的模型资源先不改任何参数用原脚本原数据集跑通一遍记录下训练耗时和验证指标再做参数修改和对比实验。这份项目包素材很完整从原始数据到最终前端展示一应俱全非常适合用作毕设起点。它并不是一个可以直接拿去实盘赚钱的系统但作为课程设计或毕业设计它把完整的工程项目流程都覆盖到了。希望你跑通后能把它改成适合自己的东西用好这份参考资料。本文还有配套的精品资源点击获取
返回列表