有域名一定要买空间做网站,选择扬中网站建设,白银网站网站建设,建设部网站13清单前言 系列专栏:【深度学习#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域#xff0c;讨论了各种复杂的深度神经网络思想#xff0c;如卷积神经网络、循环神经网络、生成对…
前言 系列专栏:【深度学习算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域讨论了各种复杂的深度神经网络思想如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记忆、自然语言处理、深度强化学习、大型语言模型和迁移学习。 近来机器学习得到了长足的发展并引起了广泛的关注其中语音和图像识别领域的成果最为显著。本研究论文分析了深度学习方法–长短期记忆神经网络LSTM–在A股市中的表现。论文显示虽然这种技术在语音识别等其他领域取得了不错的成绩但在应用于金融数据时却表现不佳。事实上金融数据的特点是噪声信号比高这使得机器学习模型难以找到模式并预测未来价格。
本文不对LSTM模型过多介绍只探讨Stacked LSTM在A股中的表现以及模型调参与性能优化。本研究文章的结构如下。第一节介绍金融时间序列数据。第二部分介绍金融时间数据的特征过程。第三部分是构建模型、定义参数空间、损失函数与优化器。第四部分是模型评估与结果可视化。第五部分是预测下一个时间点的收盘价。 目录 1. 金融时间序列数据1.1 获取股票每日价格数据1.2 观察股票收盘价格趋势 2. 时间数据特征工程2.1 构造序列数据2.2 特征缩放归一化2.3 数据集划分TimeSeriesSplit 3. 时间序列模型构建Stacked LSTM3.1 构建模型3.2 定义参数空间3.3 验证损失与调参循环3.4 最佳模型输出与保存 4. 模型评估与可视化4.1 均方误差4.2 反归一化4.3 结果验证可视化 5. 模型预测5.1 预测下一个时间点的收盘价 1. 金融时间序列数据
金融时间序列数据是指按照时间顺序记录的各种金融指标的数值序列这些指标包括但不限于股票价格、汇率、利率等。这些数据具有以下几个显著特点
时间连续性数据按照时间的先后顺序排列反映了金融市场的动态变化过程。噪声和不确定性金融市场受到多种复杂因素的影响因此数据中存在大量噪声和不确定性。非线性和非平稳性金融时间序列数据通常呈现出明显的非线性和非平稳性特征。
import numpy as np
import pandas as pdfrom pytdx.hq import TdxHq_APIimport plotly.graph_objects as gofrom sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import TimeSeriesSplit
from sklearn.model_selection import ParameterSamplerfrom keras.models import Sequential
from keras.layers import Input, Dense, LSTM, Dropout
from keras.metrics import RootMeanSquaredError
from keras.optimizers import Adam1.1 获取股票每日价格数据
首先让我们使用 TdxHq_API() 函数获取股票价格
api TdxHq_API()
with api.connect(119.147.212.81, 7709):df api.to_df(api.get_security_bars(9, 1, 600584, 0, 800))print(df)open close high low vol amount year month day \
0 41.01 39.60 41.29 39.60 432930.0 1.735115e09 2021 2 25
1 38.63 39.56 39.56 38.51 398273.0 1.553533e09 2021 2 26
2 39.71 40.47 40.59 39.15 382590.0 1.530225e09 2021 3 1
3 41.17 40.30 41.26 39.90 334984.0 1.358569e09 2021 3 2
4 40.20 40.80 40.92 39.38 325774.0 1.306173e09 2021 3 3
.. ... ... ... ... ... ... ... ... ...
795 29.15 29.05 29.29 28.68 489791.0 1.418345e09 2024 6 14
796 29.05 31.28 31.90 28.75 980331.0 2.989219e09 2024 6 17
797 31.20 31.40 31.41 30.81 580956.0 1.811908e09 2024 6 18
798 31.30 31.75 32.02 31.05 739795.0 2.341768e09 2024 6 19
799 31.30 31.08 31.88 30.93 530154.0 1.660881e09 2024 6 20 hour minute datetime
0 15 0 2021-02-25 15:00
1 15 0 2021-02-26 15:00
2 15 0 2021-03-01 15:00
3 15 0 2021-03-02 15:00
4 15 0 2021-03-03 15:00
.. ... ... ...
795 15 0 2024-06-14 15:00
796 15 0 2024-06-17 15:00
797 15 0 2024-06-18 15:00
798 15 0 2024-06-19 15:00
799 15 0 2024-06-20 15:00 [800 rows x 12 columns]1.2 观察股票收盘价格趋势
接下来使用 go.Scatter() 函数绘制股票价格趋势
fig go.Figure([go.Scatter(xdf[datetime], ydf[close])])
fig.update_layout(title{text: Close Price History, font_size: 24, font_family: Comic Sans MS, font_color: #454545},xaxis_title{text: , font_size: 18, font_family: Courier New, font_color: #454545},yaxis_title{text: Close Price CNY, font_size: 18, font_family: Lucida Console, font_color: #454545},xaxis_tickfontdict(color#663300), yaxis_tickfontdict(color#663300), width900, height500,plot_bgcolor#F2F2F2, paper_bgcolor#F2F2F2,
)
fig.show()2. 时间数据特征工程
# 设置时间窗口大小
window_size 1802.1 构造序列数据
若在收盘之前运行则最后一个测试price不准确range中长度最好再减1
# 构造序列数据
def create_dataset(dataset, look_back1):X, Y [], []for i in range(len(dataset)-look_back):a dataset[i:(ilook_back), 0]X.append(a)Y.append(dataset[i look_back, 0])return np.array(X), np.array(Y)2.2 特征缩放归一化
MinMaxScaler() 函数主要用于将特征数据按比例缩放到指定的范围。默认情况下它将数据缩放到[0, 1]区间内但也可以通过参数设置将数据缩放到其他范围。在机器学习中MinMaxScaler()函数常用于不同尺度特征数据的标准化以提高模型的泛化能力
# 归一化数据
scaler MinMaxScaler(feature_range(0, 1))
scaled_data scaler.fit_transform(df[close].values.reshape(-1, 1))# 创建数据集
X, y create_dataset(scaled_data, look_backwindow_size)# 重塑输入数据为[samples, time steps, features]
X np.reshape(X, (X.shape[0], X.shape[1], 1))2.3 数据集划分TimeSeriesSplit
TimeSeriesSplit() 函数与传统的交叉验证方法不同TimeSeriesSplit 特别适用于需要考虑时间顺序的数据集因为它确保测试集中的所有数据点都在训练集数据点之后并且可以分割多个训练集和测试集。
# 使用TimeSeriesSplit划分数据集根据需要调整n_splits
tscv TimeSeriesSplit(n_splits3, test_size30)
# 遍历所有划分进行交叉验证
for i, (train_index, test_index) in enumerate(tscv.split(X)):X_train, X_test X[train_index], X[test_index]y_train, y_test y[train_index], y[test_index]# print(fFold {i}:)# print(f Train: index{train_index})# print(f Test: index{test_index})这里我们使用最后一个 fold
X_train.shape, X_test.shape, y_train.shape, y_test.shape((590, 180, 1), (30, 180, 1), (590,), (30,))3. 时间序列模型构建Stacked LSTM
Stacked LSTM即堆叠长短期记忆网络是一种深度学习的模型架构由多个LSTM层堆叠而成。这种架构使得模型能够学习并提取输入序列数据的不同级别的特征从而提高预测的准确性。
3.1 构建模型
# 定义模型构建函数
def LSTMRegressor(lstm_units, dropout_rate, learning_rate):model Sequential()model.add(Input(shape(X_train.shape[1], X_train.shape[2])))model.add(LSTM(lstm_units, return_sequencesTrue))model.add(Dropout(dropout_rate))model.add(LSTM(lstm_units, return_sequencesTrue))model.add(Dropout(dropout_rate))model.add(LSTM(lstm_units))model.add(Dropout(dropout_rate))model.add(Dense(60))model.add(Dropout(dropout_rate))model.add(Dense(1)) # 线性回归层opt Adam(learning_ratelearning_rate)model.compile(optimizeropt, lossmean_squared_error)return model3.2 定义参数空间
使用 ParameterSampler 可以为随机搜索定义参数的分布却不像网格搜索那样指定所有可能的参数组合。
# 定义参数空间
param_grid {lstm_units: [32, 64, 128],dropout_rate: [0.2, 0.3, 0.4],learning_rate: [0.001, 0.0001]
}
# 使用ParameterSampler生成参数组合
param_list list(ParameterSampler(param_grid, n_iterlen(param_grid[lstm_units]) * len(param_grid[dropout_rate]) * len(param_grid[learning_rate]), random_state42)
)3.3 验证损失与调参循环
# 初始化最佳验证损失和最佳模型
best_val_loss float(inf)
best_model None# 调参循环
for params in param_list:print(fTrying parameters: {params})model LSTMRegressor(**params)# 训练模型这里仅使用一部分epoch作为示例history model.fit(X_train, y_train, epochs10, batch_size32, validation_data(X_test, y_test), verbose0)# 计算验证集上的损失val_loss history.history[val_loss][-1]# 如果当前模型的验证损失比之前的好则更新最佳模型和最佳验证损失if val_loss best_val_loss:best_val_loss val_lossbest_model modelprint(fFound better model with validation loss: {best_val_loss})# 输出最佳模型的参数
print(fBest model parameters: {param_list[param_list.index(params)]})Trying parameters: {lstm_units: 32, learning_rate: 0.001, dropout_rate: 0.2}
Found better model with validation loss: 0.007122963201254606
Trying parameters: {lstm_units: 64, learning_rate: 0.001, dropout_rate: 0.2}
Found better model with validation loss: 0.006877976469695568
Trying parameters: {lstm_units: 128, learning_rate: 0.001, dropout_rate: 0.2}
Found better model with validation loss: 0.003105488372966647
Trying parameters: {lstm_units: 32, learning_rate: 0.0001, dropout_rate: 0.2}
Trying parameters: {lstm_units: 64, learning_rate: 0.0001, dropout_rate: 0.2}
Trying parameters: {lstm_units: 128, learning_rate: 0.0001, dropout_rate: 0.2}
Trying parameters: {lstm_units: 32, learning_rate: 0.001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 64, learning_rate: 0.001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 128, learning_rate: 0.001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 32, learning_rate: 0.0001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 64, learning_rate: 0.0001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 128, learning_rate: 0.0001, dropout_rate: 0.3}
Trying parameters: {lstm_units: 32, learning_rate: 0.001, dropout_rate: 0.4}
Trying parameters: {lstm_units: 64, learning_rate: 0.001, dropout_rate: 0.4}
Trying parameters: {lstm_units: 128, learning_rate: 0.001, dropout_rate: 0.4}
Trying parameters: {lstm_units: 32, learning_rate: 0.0001, dropout_rate: 0.4}
Trying parameters: {lstm_units: 64, learning_rate: 0.0001, dropout_rate: 0.4}
Trying parameters: {lstm_units: 128, learning_rate: 0.0001, dropout_rate: 0.4}
Best model parameters: {lstm_units: 128, learning_rate: 0.0001, dropout_rate: 0.4}3.4 最佳模型输出与保存
best_model.summary()Model: sequential_2
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃ Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ lstm_6 (LSTM) │ (None, 180, 128) │ 66,560 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dropout_8 (Dropout) │ (None, 180, 128) │ 0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ lstm_7 (LSTM) │ (None, 180, 128) │ 131,584 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dropout_9 (Dropout) │ (None, 180, 128) │ 0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ lstm_8 (LSTM) │ (None, 128) │ 131,584 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dropout_10 (Dropout) │ (None, 128) │ 0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dense_4 (Dense) │ (None, 60) │ 7,740 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dropout_11 (Dropout) │ (None, 60) │ 0 │
├──────────────────────────────────────┼─────────────────────────────┼─────────────────┤
│ dense_5 (Dense) │ (None, 1) │ 61 │
└──────────────────────────────────────┴─────────────────────────────┴─────────────────┘Total params: 1,012,589 (3.86 MB)Trainable params: 337,529 (1.29 MB)Non-trainable params: 0 (0.00 B)Optimizer params: 675,060 (2.58 MB)使用 .save() 函数保存最佳模型
# 保存最佳模型
# best_model.save(best_model.h5)4. 模型评估与可视化
4.1 均方误差
使用均方误差 mean_squared_error() 评估模型性能
from sklearn.metrics import mean_squared_error
# 使用最佳模型进行预测
trainPredict best_model.predict(X_train)
testPredict best_model.predict(X_test)
mse mean_squared_error(y_test, testPredict)
print(fTest MSE: {mse})19/19 ━━━━━━━━━━━━━━━━━━━━ 2s 105ms/step
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 94ms/step
Test MSE: 0.00310548774696559234.2 反归一化
# 反归一化预测结果
trainPredict scaler.inverse_transform(trainPredict)
y_train scaler.inverse_transform([y_train])
testPredict scaler.inverse_transform(testPredict)
y_test scaler.inverse_transform([y_test])4.3 结果验证可视化
# 计算绘图数据
train df[:X_train.shape[0]X_train.shape[1]]
valid df[X_train.shape[0]X_train.shape[1]:]
valid valid.assign(predictionstestPredict)# 可视化数据
fig go.Figure([go.Scatter(xtrain[datetime], ytrain[close],nameTrain)])
fig.add_trace(go.Scatter(xvalid[datetime],yvalid[close],nameTest))
fig.add_trace(go.Scatter(xvalid[datetime],yvalid[predictions], namePrediction))
fig.update_layout(title{text: Close Price Validation, font_size: 24, font_family: Comic Sans MS, font_color: #454545},xaxis_title{text: , font_size: 18, font_family: Courier New, font_color: #454545},yaxis_title{text: Close Price CNY, font_size: 18, font_family: Lucida Console, font_color: #454545},xaxis_tickfontdict(color#663300), yaxis_tickfontdict(color#663300), width900, height500,plot_bgcolor#F2F2F2, paper_bgcolor#F2F2F2,
)
fig.show()从上图我们可以观察到预测价格存在滞后性关于如何缓解滞后性请参考连接。1
5. 模型预测
5.1 预测下一个时间点的收盘价
# 使用模型预测下一个时间点的收盘价
# 假设latest_closes是一个包含最新window_size个收盘价的列表或数组
latest_closes df[close][-window_size:].values
latest_closes latest_closes.reshape(-1, 1)
scaled_latest_closes scaler.fit_transform(latest_closes)
latest_closes_reshape scaled_latest_closes.reshape(1, window_size, 1)
next_close_pred best_model.predict(latest_closes_reshape)
next_close_pred scaler.inverse_transform(next_close_pred)
next_close_pred1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step
array([[30.284128]], dtypefloat32)本文仅用于深度学习科学实验和教育目的并非投资建议 LSTM从理论基础到代码实战 5 关于lstm预测滞后性的讨论 ↩︎