BiLSTM 实现股票多变量时间序列预测(PyTorch版)

羊市
前言

系列专栏:【深度学习:算法项目实战】✨︎
涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记忆、自然语言处理、深度强化学习、大型语言模型和迁移学习。

在数据科学领域中,时间序列预测一直是一个重要且挑战性的任务。随着深度学习技术的兴起,特别是循环神经网络(RNN)及其变种如长短期记忆网络(LSTM)和门控循环单元(GRU)的引入,时间序列预测的性能得到了显著提升。在这些模型中,双向长短期记忆网络(BiLSTM)因其能够同时捕获序列中的前向和后向信息,而在许多应用中表现出色。

在本文中,我们将探讨如何使用PyTorch框架实现基于双向长短期记忆网络(BiLSTM)的多变量时间序列预测模型。多变量时间序列预测涉及多个输入变量和一个或多个输出变量,这些变量随时间变化并可能相互影响。通过利用BiLSTM的双向特性,我们的模型将能够同时考虑历史数据和未来趋势,从而更准确地预测时间序列的未来值。

BiLSTM 实现股票多变量时间序列预测

  • 1. 股票时间序列数据
    • 1.1 数据预处理
    • 1.2 数据可视化
  • 2. 时间数据特征工程(APPL)
    • 2.1 特征缩放(归一化)
    • 2.2 数据集划分(TimeSeriesSplit)
    • 2.3 数据集张量(TensorDataset)
  • 3. 构建时间序列模型(BiLSTM)
    • 3.1 构建Bi-LSTM 模型
    • 3.2 定义模型、损失函数与优化器
  • 4. 模型训练与可视化
    • 4.1 模型训练与权重更新(保存最佳模型)
    • 4.2 可视化训练过程(Loss损失)
  • 5. 模型评估与可视化
    • 5.1 评估指标(MAE、RMSE、MAPE)
    • 5.2 反归一化
    • 5.3 结果可视化
  • 6. 模型预测
    • 6.1 转换最新时间步收盘价的数组为张量
    • 6.2 预测下一个时间点的收盘价格

1. 股票时间序列数据

股票时间序列数据是指按照时间顺序排列的关于股票市场的历史数据。这些数据记录了股票市场在不同时间点上的各种信息,如股票的开盘价、最高价、最低价、收盘价、成交量等。时间序列数据是金融市场分析的重要基础,因为它们反映了市场参与者的行为、市场供求关系以及宏观经济和政策的影响等因素。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsfrom sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import TimeSeriesSplitimport torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
from torchinfo import summary
from tqdm import tqdm
np.random.seed(0)
torch.manual_seed(0)

1.1 数据预处理

pandas.to_datetime 函数将标量、数组、Series 或 DataFrame/dict-like 转换为 pandas datetime 对象。

AAPL = pd.read_csv('AAPL.csv')
print(type(AAPL['Close'].iloc[0]),type(AAPL['Date'].iloc[0]))
# Let's convert the data type of timestamp column to datatime format
AAPL['Date'] = pd.to_datetime(AAPL['Date'])
print(type(AAPL['Close'].iloc[0]),type(AAPL['Date'].iloc[0]))# Selecting subset
cond_1 = AAPL['Date'] >= '2021-04-23 00:00:00'
cond_2 = AAPL['Date'] <= '2024-04-23 00:00:00'
AAPL = AAPL[cond_1 & cond_2].set_index('Date')
print(AAPL.shape)
<class 'numpy.float64'> <class 'str'>
<class 'numpy.float64'> <class 'pandas._libs.tslibs.timestamps.Timestamp'>
(755, 6)

1.2 数据可视化

收盘价是股票在正常交易日的最后交易价格。股票的收盘价是投资者跟踪其长期表现的标准基准。

# plt.style.available
plt.style.use('_mpl-gallery')
plt.figure(figsize=(18,6))
plt.title('Close Price History')
plt.plot(AAPL['Close'],label='AAPL')
plt.ylabel('Close Price USD ($)', fontsize=18)
plt.legend()
plt.show()

收盘价

2. 时间数据特征工程(APPL)

在时间序列分析中,时间窗口通常用于描述在训练模型时考虑的连续时间步 time steps 的数量。这个时间窗口的大小,即 window_size,对于模型预测的准确性至关重要。

具体来说,window_size 决定了模型在做出预测时所使用的历史数据的长度。例如,如果我们想要用前60天的股票数据来预测未来7天的收盘价,那么window_size 就是60。

# 设置时间窗口大小
window_size = 60

除此之外还需构建序列函数,该函数需要两个参数:datasetlookback,前者是要转换成数据集的 NumPy 数组,后者是用作预测下一个时间段的输入变量的前一时间步数,默认设为 1。

# 构造序列数据函数,若target为 Close,即索引为 3
def create_dataset(dataset, lookback= 1):X, y = [], []for i in range(len(dataset)-lookback): feature = dataset[i:(i+lookback), :]target = dataset[i + lookback, 3]X.append(feature)y.append(target)return np.array(X), np.array(y)

2.1 特征缩放(归一化)

MinMaxScaler() 函数主要用于将特征数据按比例缩放到指定的范围。默认情况下,它将数据缩放到[0, 1]区间内,但也可以通过参数设置将数据缩放到其他范围。在机器学习中,MinMaxScaler()函数常用于不同尺度特征数据的标准化,以提高模型的泛化能力。

# 选取 AAPL[['Open', 'High', 'Low', 'Close']]作为特征, 归一化数据
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(AAPL[['Open', 'High', 'Low', 'Close']].values)# 获取反归一化参数(即原始数据的最小值和最大值)
original_min = scaler.data_min_
original_max = scaler.data_max_# scale_params是一个包含所有特征反归一化参数的列表或数组,
# 其中第四个元素是Close价格的反归一化参数
scale_params = original_max - original_min

2.2 数据集划分(TimeSeriesSplit)

TimeSeriesSplit() 函数与传统的交叉验证方法不同,TimeSeriesSplit 特别适用于需要考虑时间顺序的数据集,因为它确保测试集中的所有数据点都在训练集数据点之后,并且可以分割多个训练集和测试集。

# 创建数据集,数据形状为 [samples, time steps, features]
X, y = create_dataset(scaled_data, lookback = window_size)
print(X.shape, y.shape)
(695, 60, 4) (695,)
# 使用TimeSeriesSplit划分数据集,根据需要调整n_splits
tscv = TimeSeriesSplit(n_splits=3, test_size=90)
# 遍历所有划分进行交叉验证
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(f"Fold {i}:")# print(f"  Train: index={train_index}")# print(f"  Test:  index={test_index}")# 查看最后一个 fold 数据帧的维度
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
(605, 60, 4) (90, 60, 4) (605,) (90,)

2.3 数据集张量(TensorDataset)

张量是一个多维数组或矩阵的数学对象,可以看作是向量和矩阵的推广。在深度学习中,张量通常用于表示输入数据、模型参数以及输出数据

# 将 NumPy数组转换为 tensor张量
X_train_tensor = torch.from_numpy(X_train).type(torch.Tensor)
X_test_tensor = torch.from_numpy(X_test).type(torch.Tensor)
y_train_tensor = torch.from_numpy(y_train).type(torch.Tensor).view(-1, 1)
y_test_tensor = torch.from_numpy(y_test).type(torch.Tensor).view(-1, 1)print(X_train_tensor.shape, X_test_tensor.shape, y_train_tensor.shape, y_test_tensor.shape)

view() 函数用于重塑张量对象,它等同于 NumPy 中的 reshape() 函数,允许我们重组数据,以匹配 BiLSTM 模型所需的输入形状。以这种方式重塑数据可确保 BiLSTM 模型以预期格式接收数据。

torch.Size([605, 60, 4]) torch.Size([90, 60, 4]) torch.Size([605, 1]) torch.Size([90, 1])

接下来,我们将使用 TensorDatasetDataLoader创建数据集和数据加载器

train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_dataset = TensorDataset(X_test_tensor, y_test_tensor)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

shuffle=True 表示在每个epoch开始时,数据集将被随机打乱,这有助于防止模型在训练时过拟合。与训练数据加载器类似,shuffle=False 表示在测试时不需要打乱数据集。因为测试集通常用于评估模型的性能,而不是用于训练,所以不需要打乱。

3. 构建时间序列模型(BiLSTM)

双向LSTM(Bi-directional Long Short-Term Memory)网络可以通过使用 nn.LSTM 类并设置 bidirectional=True 参数来完成

PyTorch所提供的数学公式及解释如下:🔗


Apply a multi-layer long short-term memory (LSTM) RNN to an input sequence. For each element in the input sequence, each layer computes the following function:
i t = σ ( W i i x t + b i i + W h i h t − 1 + b h i ) f t = σ ( W i f x t + b i f + W h f h t − 1 + b h f ) g t = tanh ⁡ ( W i g x t + b i g + W h g h t − 1 + b h g ) o t = σ ( W i o x t + b i o + W h o h t − 1 + b h o ) c t = f t ⊙ c t − 1 + i t ⊙ g t h t = o t ⊙ tanh ⁡ ( c t ) \begin{array}{ll} \\ i_t = \sigma(W_{ii} x_t + b_{ii} + W_{hi} h_{t-1} + b_{hi}) \\ f_t = \sigma(W_{if} x_t + b_{if} + W_{hf} h_{t-1} + b_{hf}) \\ g_t = \tanh(W_{ig} x_t + b_{ig} + W_{hg} h_{t-1} + b_{hg}) \\ o_t = \sigma(W_{io} x_t + b_{io} + W_{ho} h_{t-1} + b_{ho}) \\ c_t = f_t \odot c_{t-1} + i_t \odot g_t \\ h_t = o_t \odot \tanh(c_t) \\ \end{array} it=σ(Wiixt+bii+Whiht1+bhi)ft=σ(Wifxt+bif+Whfht1+bhf)gt=tanh(Wigxt+big+Whght1+bhg)ot=σ(Wioxt+bio+Whoht1+bho)ct=ftct1+itgtht=ottanh(ct)
where h t h_t ht is the hidden state at time t t t, c t c_t ct is the cell state at time t t t, x t x_t xt is the input at time t t t, h t − 1 h_{t-1} ht1 is the hidden state of the layer at time t − 1 t-1 t1 or the initial hidden state at time 0 0 0, and i t i_t it, f t f_t ft, g t g_t gt, o t o_t ot are the input, forget, cell, and output gates, respectively. σ \sigma σ is the sigmoid function, and ⊙ \odot is the Hadamard product.

In a multilayer LSTM, the input x t ( l ) x^{(l)}_t xt(l) of the l l l -th layer ( l ≥ 2 l \ge 2 l2) is the hidden state h t ( l − 1 ) h^{(l-1)}_t ht(l1) of the previous layer multiplied by dropout δ t ( l − 1 ) \delta^{(l-1)}_t δt(l1) where each δ t ( l − 1 ) \delta^{(l-1)}_t δt(l1) is a Bernoulli random variable which is 0 0 0 with probability d r o p o u t dropout dropout.

If proj_size > 0 is specified, LSTM with projections will be used. This changes the LSTM cell in the following way. First, the dimension of h t h_t ht will be changed from hidden_size to proj_size (dimensions of W h i W_{hi} Whi will be changed accordingly). Second, the output hidden state of each layer will be multiplied by a learnable projection matrix: h t = W h r h t h_t = W_{hr}h_t ht=Whrht. Note that as a consequence of this, the output of LSTM network will be of different shape as well. See Inputs/Outputs sections below for exact dimensions of all variables. You can find more details in https://arxiv.org/abs/1402.1128.


3.1 构建Bi-LSTM 模型

class BiLSTM(nn.Module):def __init__(self, input_size, hidden_size, num_layers, output_size):# input_size 是输入特征的维度,hidden_size 是LSTM隐藏层神经单元维度(或称为隐藏状态的大小),# num_layers 是LSTM网络层数,output_size 是输出维度super(BiLSTM, self).__init__()# 通过调用 super(BiLSTM, self).__init__() 初始化父类 nn.Moduleself.hidden_size = hidden_sizeself.num_layers = num_layersself.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True)# 定义 LSTM 层,使用 batch_first=True 表示输入数据的形状是 [batch_size, seq_len(time_steps), input_size]# 使用 bidirectional=True 表示的是 bidirectional LSTM,即双向 LSTMself.fc = nn.Linear(hidden_size * 2, output_size)  # 定义全连接层,将 LSTM 的最后一个隐藏状态映射到输出维度 output_size,双向LSTM的输出维度是隐藏层维度的两倍def forward(self, x):# 初始化隐藏状态(hidden state)和单元状态(cell state)为全零张量h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(x.device)  # 双向LSTM,所以是2倍c0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(x.device)  # LSTM输出, (output, (hn, cn))out, _ = self.lstm(x, (h0, c0))  # out: tensor of shape (batch_size, seq_length(time_steps), hidden_size*2)# 取最后一个时间步的输出(或者对输出进行平均/最大池化等操作)# 这里我们选择最后一个时间步的输出out = self.fc(out[:, -1, :])return out

在时间序列模型中 seq_len 代表的就是时间步 time_steps
batch_first=True 表示输入数据的形状是 [batch_size, seq_len, input_size],输出数据形状是 [batch_size, seq_len, num_directions * hidden_size]
batch_first=False 表示输入数据的形状是 [seq_len, batch_size, input_size],输出数据形状是 [seq_len, batch_size, num_directions * hidden_size]

3.2 定义模型、损失函数与优化器

在神经网络中,模型通常指的是神经网络的架构,它定义了输入数据如何通过网络进行转换和计算,从而得到输出。在本案例中我们可以通过调用 BiLSTM 类来定义 Bi-directional Long Short-Term Memory

损失函数(又称代价函数)是衡量模型预测值与真实值之间不一致性的指标。在训练神经网络时,我们的目标是找到一组网络参数,它使得损失函数的值最小化。损失函数的选择取决于问题的类型,例如,对于回归问题,常用的损失函数包括均方误差(MSE);对于分类问题,则常使用交叉熵损失等。在PyTorch中,可以使用torch.nn模块中的损失函数类,如nn.MSELoss用于回归问题,nn.CrossEntropyLoss用于分类问题

优化器的任务是通过更新网络的权重和偏置来最小化损失函数。这通常是通过反向传播算法完成的,该算法计算损失相对于每个参数的梯度,并使用梯度下降或其变体来更新参数。在PyTorch中,torch.optim模块提供了多种优化器实现,如随机梯度下降(SGD)、带动量的SGD(Momentum)、RMSProp、Adam等。这些优化器都是基于梯度下降算法进行改进的,旨在更有效地更新模型参数。

model = BiLSTM(input_size = X_train_tensor.size(2), # 输入数据的特征数量 X_train.shape[2]hidden_size = 64,num_layers = 3,output_size = 1)
criterion = torch.nn.MSELoss() # 定义均方误差损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 定义优化器
summary(model, (32, 60, 4)) # batch_size, seq_len(time_steps), input_size
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
BiLSTM                                   [32, 1]                   --
├─LSTM: 1-1                              [32, 60, 128]             234,496
├─Linear: 1-2                            [32, 1]                   129
==========================================================================================
Total params: 234,625
Trainable params: 234,625
Non-trainable params: 0
Total mult-adds (Units.MEGABYTES): 450.24
==========================================================================================
Input size (MB): 0.03
Forward/backward pass size (MB): 1.97
Params size (MB): 0.94
Estimated Total Size (MB): 2.94
==========================================================================================

4. 模型训练与可视化

4.1 模型训练与权重更新(保存最佳模型)

train_losses = [] # 初始化列表来存储损失值
test_losses = [] # 初始化列表来存储损失值
best_loss = float('100') # 初始化为一个很大的值
best_model = None # 初始化最佳模型为None# 训练循环
num_epochs = 20  # 假设我们要训练 20个 epoch
for epoch in range(num_epochs):model.train()  # 初始化训练进程train_loss = 0.0  # 初始化每个epoch的损失总和pbar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{num_epochs}")for batch_idx, (data, target) in enumerate(pbar):optimizer.zero_grad()  # 将优化器中所有参数的梯度归零output = model(data)  # 每个批次的预测值loss = criterion(output, target)  # 计算模型损失值(y_train_pred 与 y_train)# 累加每个批次的损失train_loss += loss.item() * data.size(0)# 反向传播和优化loss.backward()optimizer.step()# 更新进度条(显示当前批次的损失)pbar.update()# 计算当前epoch的平均损失average_loss = train_loss / len(train_loader.dataset)train_losses.append(average_loss)model.eval()  # 将模型设置为评估模式with torch.no_grad():  # 不计算梯度以节省内存和计算资源test_loss = 0.0for data, target in test_loader:output = model(data) # 每个批次的预测值loss = criterion(output, target)test_loss += loss.item() * data.size(0)# 计算测试集的平均损失test_loss = test_loss / len(test_loader.dataset)test_losses.append(test_loss)# 如果测试损失比之前的最小值小,则更新最佳模型权重if test_loss < best_loss:best_loss = test_lossbest_model = model.state_dict() # 训练循环结束后保存最佳模型
if best_model is not None:torch.save(best_model, 'model_best.pth')print(f'Best model saved with test loss {best_loss:.4f}')
else:print('No model saved as no improvement was made.')

loss.item():loss是一个PyTorch的Tensor对象,而.item()方法用于从只包含一个元素的Tensor中提取Python数值(通常是浮点数)。由于损失通常是一个标量(scalar),因此我们可以安全地使用.item()来获取其数值。
data.size(0):这返回data这个Tensor在第一维度(通常是批次维度)的大小。在深度学习中,我们经常使用mini-batch梯度下降,这意味着我们将整个数据集分成较小的批次,并在每个批次上计算梯度并更新模型。data.size(0)就告诉我们当前批次中有多少个数据样本。
loss.item() * data.size(0):这实际上是在对损失进行“加权”。我们乘以批次大小是为了稍后能够计算平均损失(average loss)。这是因为在累积损失时,我们不仅要考虑损失的大小,还要考虑该损失是基于多少数据样本计算出来的。
train_loss += ...:最后,我们将加权后的损失累加到train_loss变量中。这样做是为了在整个训练循环结束时计算平均损失。

Epoch 1/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 13.24it/s]
Epoch 2/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 14.14it/s]
Epoch 3/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 13.10it/s]
Epoch 4/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 14.17it/s]
Epoch 5/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 14.00it/s]
Epoch 6/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 14.26it/s]
Epoch 7/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 14.48it/s]
Epoch 8/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 13.82it/s]
Epoch 9/20: 100%|███████████████████████████████| 19/19 [00:01<00:00, 13.80it/s]
Epoch 10/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 14.18it/s]
Epoch 11/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 14.16it/s]
Epoch 12/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 14.30it/s]
Epoch 13/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 13.36it/s]
Epoch 14/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 12.76it/s]
Epoch 15/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 15.39it/s]
Epoch 16/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 14.80it/s]
Epoch 17/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 13.82it/s]
Epoch 18/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 12.27it/s]
Epoch 19/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 14.48it/s]
Epoch 20/20: 100%|██████████████████████████████| 19/19 [00:01<00:00, 13.97it/s]
Best model saved with test loss 0.0010
best_epoch_idx = test_losses.index(min(test_losses))
print(f"Best epoch: {best_epoch_idx+1}, with test loss: {min(test_losses):.4f}")
Best epoch: 20, with test loss: 0.0010

4.2 可视化训练过程(Loss损失)

# 绘制损失图
plt.figure(figsize=(18, 6))
plt.plot(train_losses, label='Train Loss')
plt.plot(test_losses, label='Test Loss')
plt.title('Training and Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()

请添加图片描述

5. 模型评估与可视化

5.1 评估指标(MAE、RMSE、MAPE)

RMSE:该指标计算预测值与实际值之间平均平方差的平方根。它对较大误差给予较高的惩罚。
MAPE:该指标计算实际值与预测值之间绝对百分比差异的平均值。它用百分比来表示平均绝对误差,这对了解相对预测误差非常有用。

# 加载最佳模型
model.load_state_dict(torch.load('model_best.pth'))
def mean_absolute_percentage_error(y_true, y_pred):y_true, y_pred = np.array(y_true), np.array(y_pred)mask = y_true != 0return np.mean(np.abs((y_true[mask] - y_pred[mask]) / y_true[mask])) * 100 if mask.any() else 0# 将模型设置为评估模式
model.eval()
y_pred_all = []
y_true_all = []with torch.no_grad():pbar = tqdm(test_loader, desc='Evaluating')for data, target in pbar:y_pred = model(data).detach().cpu().numpy()  # 确保张量在CPU上y_true = target.detach().cpu().numpy()  # 确保张量在CPU上y_pred_all.append(y_pred)y_true_all.append(y_true)pbar.update()# 合并所有批次的预测和真实值
y_pred_all = np.concatenate(y_pred_all)
y_true_all = np.concatenate(y_true_all)mae = np.mean(np.abs(y_pred_all - y_true_all))
print(f"MAE: {mae:.4f}")rmse = np.sqrt(np.mean((y_pred_all - y_true_all) ** 2))
print(f"RMSE: {rmse:.4f}")mape = mean_absolute_percentage_error(y_true_all, y_pred_all)
print(f"MAPE: {mape:.4f}%")
Evaluating: 100%|████████████████████████████| 3/3 [00:00<00:00, 63.98it/s]
MAE: 0.0241
RMSE: 0.0321
MAPE: 3.2193%

5.2 反归一化

.inverse_transform 函数将经过转换或缩放的数据转换回其原始形式或接近原始形式,若在这里使用会发生错误,是因为用一个形状为(605,4)的数组去广播(broadcast)到一个形状为(605, 1)的数组上,这两个形状不兼容,它们的第二个维度不匹配,这里我们将使用下面的函数进行反归一化

# 提取Close价格的反归一化参数
close_denorm_param = scale_params[3]  # 假设Close是第四个特征# 如果反归一化包括一个偏移量shift,需要再加上 shift_param
# denormalized_predictions = (predictions[:, 0] * scale_param) + shift_param
# 将训练预测 Close的价格反归一化
y_train_pred = model(X_train_tensor).detach().numpy()
y_train_denormalized_predictions = (y_train_pred * scale_params[3]) + original_min[3]# 将测试预测 Close的价格反归一化
y_test_pred = model(X_test_tensor).detach().numpy()
y_test_denormalized_predictions = (y_test_pred * scale_params[3]) + original_min[3]

5.3 结果可视化

计算训练预测与测试预测的绘图数据

# shift train predictions for plotting
trainPredict = AAPL[window_size:X_train.shape[0]+X_train.shape[1]]
trainPredictPlot = trainPredict.assign(TrainPrediction= y_train_denormalized_predictions)testPredict = AAPL[X_train.shape[0]+X_train.shape[1]:]
testPredictPlot = testPredict.assign(TestPrediction= y_test_denormalized_predictions)

绘制模型收盘价格的原始数据与预测数据

# Visualize the data
plt.figure(figsize=(18,6))
plt.title('BiLSTM Close Price Validation')
plt.plot(AAPL['Close'], color='blue', label='original')
plt.plot(trainPredictPlot['TrainPrediction'], color='orange',label='Train Prediction')
plt.plot(testPredictPlot['TestPrediction'], color='red', label='Test Prediction')
plt.legend()
plt.show()

请添加图片描述

6. 模型预测

6.1 转换最新时间步收盘价的数组为张量

# 假设latest_closes是一个包含最新window_size个收盘价的列表或数组
latest_closes = AAPL[['Open', 'High', 'Low', 'Close']][-window_size:].values
scaled_latest_closes = scaler.transform(latest_closes)
tensor_latest_closes = torch.from_numpy(scaled_latest_closes).type(torch.Tensor).view(1, window_size, 4) 
print(tensor_latest_closes.shape)
torch.Size([1, 60, 4])

6.2 预测下一个时间点的收盘价格

# 使用模型预测下一个时间点的收盘价
next_close_pred = model(tensor_latest_closes).detach().numpy()
next_close_denormalized_pred = (next_close_pred * scale_params[3]) + original_min[3]
next_close_denormalized_pred
array([[165.9167]], dtype=float32)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3247383.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

三、GPIO口

我们在刚接触C语言时&#xff0c;写的第一个程序必定是hello world&#xff0c;其他的编程语言也是这样类似的代码是告诉我们进入了编程的世界&#xff0c;在单片机中也不例外&#xff0c;不过我们的传统就是点亮第一个LED灯&#xff0c;点亮电阻&#xff0c;电容的兄弟&#x…

【Java项目笔记】01项目介绍

一、技术框架 1.后端服务 Spring Boot为主体框架 Spring MVC为Web框架 MyBatis、MyBatis Plus为持久层框架&#xff0c;负责数据库的读写 阿里云短信服务 2.存储服务 MySql redis缓存数据 MinIO为对象存储&#xff0c;存储非结构化数据&#xff08;图片、视频、音频&a…

防溺水预警系统引领水域安全新篇章

一、系统概述 随着人们对水域活动的需求增加&#xff0c;溺水事故频发&#xff0c;给人们的生命安全带来了严重威胁。然而&#xff0c;如今&#xff0c;一项创新科技正在以强大的功能和无限的潜力引领着水域安全的新篇章。智能防溺水预警系统&#xff0c;作为一种集成了智能感知…

神经网络构造

目录 一、神经网络骨架&#xff1a;二、卷积操作&#xff1a;三、卷积层&#xff1a;四、池化层&#xff1a;五、激活函数&#xff08;以ReLU为例&#xff09;&#xff1a; 一、神经网络骨架&#xff1a; import torch from torch import nn#神经网络 class CLH(nn.Module):de…

【概率论三】参数估计:点估计(矩估计、极大似然法)、区间估计

文章目录 一. 点估计1. 矩估计法2. 极大似然法2.1. 似然函数2.2. 极大似然估计法 3. 评价估计量的标准3.1. 无偏性3.2. 有效性3.3. 一致性 二. 区间估计1. 区间估计的概念2. 正态总体参数的区间估计 参数估计讲什么 由样本来确定未知参数参数估计分为点估计与区间估计 一. 点估…

Golang面试题整理(持续更新...)

文章目录 Golang面试题总结一、基础知识1、defer相关2、rune 类型3、context包4、Go 竞态、内存逃逸分析5、Goroutine 和线程的区别6、Go 里面并发安全的数据类型7、Go 中常用的并发模型8、Go 中安全读写共享变量方式9、Go 面向对象是如何实现的10、make 和 new 的区别11、Go 关…

【Pytorch】RNN for Name Classification

参考学习来自&#xff1a; https://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.htmlRNN完成姓名分类https://download.pytorch.org/tutorial/data.zip 导入库 import glob # 用于查找符合规则的文件名 import os import unicodedata import stri…

【linux】信号的理论概述和实操

目录 理论篇 信号概述 信号的分类 信号机制 理解硬件中断 异步 信号对应的三种动作 信号产生的条件 终端按键 系统调用 软件条件 硬件异常 除0错误 野指针 OS对于错误的态度 信号在进程中的内核数据结构 信号的处理 CPU的内核态和用户态概述 进程处理信号的时…

dom4j 操作 xml 之按照顺序插入标签

最近学了一下 dom4j 操作 xml 文件&#xff0c;特此记录一下。 public class Dom4jNullTagFiller {public static void main(String[] args) throws DocumentException {SAXReader reader new SAXReader();//加载 xml 文件Document document reader.read("C:\\Users\\24…

Hadoop3:MR程序的数据倾斜问题处理

一、数据倾斜 什么是数据倾斜&#xff1f; 学过Redis集群的都知道数据倾斜这个问题。 就是大量数据&#xff0c;分配不均匀的现象。 二、MR数据倾斜 1、怎么判断出现数据倾斜&#xff1f; 数据频率倾斜——某一个区域的数据量要远远大于其他区域。 数据大小倾斜——部分记…

[iOS]浅析isa指针

[iOS]浅析isa指针 文章目录 [iOS]浅析isa指针isa指针isa的结构isa的初始化注意事项 上一篇留的悬念不止分类的实现 还有isa指针到底是什么 它是怎么工作的 class方法又是怎么运作的 class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags 这里面的class又是何方…

【BUG】已解决:Uncaught SyntaxError: Unexpected token ‘<‘

已解决&#xff1a;Could not install packages due to an EnvironmentError: [Errno 13] Permission denied 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人 …

用 WireShark 抓住 TCP

Wireshark 是帮助我们分析网络请求的利器&#xff0c;建议每个同学都装一个。我们先用 Wireshark 抓取一个完整的连接建立、发送数据、断开连接的过程。 简单的介绍一下操作流程。 1、首先打开 Wireshark&#xff0c;在欢迎界面会列出当前机器上的所有网口、虚机网口等可以抓取…

Nginx、LNMP万字详解

目录 Nginx 特点 Nginx安装 添加Nginx服务 Nginx配置文件 全局配置 HTTP配置 状态统计页面 Nginx访问控制 授权用户 授权IP 虚拟主机 基于域名 测试 基于IP 测试 基于端口 测试 LNAMP 解析方式 LNMP转发php-fpm解析 Nginx代理LAMP解析 LNMP部署示例 实…

github汉化

GitHub: Let’s build from here GitHub 进入后在顶部搜索栏直接搜索 选第一个点进去后根据教程安装即可 注意如果是chrome浏览器的话 安装篡改猴如果这个问题参考这个链接 chrome浏览器安装篡改猴脚本不执行&#xff08;Please enable developer mode to allow userscript…

数据结构(单链表算法题)

1.删除链表中等于给定值 val 的所有节点。 OJ链接 typedef struct ListNode ListNode;struct ListNode {int val;struct ListNode* next; };struct ListNode* removeElements(struct ListNode* head, int val) {//创建新链表ListNode* newhead, *newtail;newhead newtail N…

IDEA工具中Java语言写小工具遇到的问题

一&#xff1a;读取excel时遇到 org/apache/poi/ss/usermodel/WorkbookProvider 解决办法&#xff1a; 在pom.xml中把poi的引文包放在最前面即可

小技巧:通过命令行和网络连接获取电脑所连wifi密码

方法一&#xff1a;命令行 第一步&#xff0c;命令行输入下列命令&#xff0c;获取连接过的wifi netsh wlan show profile 第二步&#xff0c;输入以下命令查看你想看的wifi密码&#xff08;红色改为你获取的任意一个wifi名称&#xff09; netsh wlan show profile happy key…

高数知识补充----矩阵、行列式、数学符号

矩阵计算 参考链接&#xff1a;矩阵如何运算&#xff1f;——线性代数_矩阵计算-CSDN博客 行列式计算 参考链接&#xff1a;实用的行列式计算方法 —— 线性代数&#xff08;det&#xff09;_det线性代数-CSDN博客 参考链接&#xff1a;行列式的计算方法(含四种&#xff0c;…

云计算监控减少网络安全事件的五种方法

当企业没有对其IT基础设施采取足够的保护措施时&#xff0c;就会发生网络安全事件。网络罪犯利用其漏洞注入恶意软件或提取敏感信息。许多这样的漏洞存在于使用云计算平台进行操作的企业中。 云计算使企业在市场上更具生产力、效率和竞争力。这是因为他们的员工即使不在同一地点…