基于门控循环单元 GRU 实现股票单变量时间序列预测(PyTorch版)

巴黎落日

前言

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

近来,机器学习得到了长足的发展,并引起了广泛的关注,其中语音和图像识别领域的成果最为显著。本文分析了深度学习模型——堆叠门控循环单元 Stacked GRU 在股市的表现。论文显示,虽然这种技术在自然语言处理、语音识别等其他领域取得了不错的成绩,但在金融时间序列预测上却表现不佳。事实上,金融数据的特点是噪声信号比高,这使得机器学习模型难以找到模式并预测未来价格。

本文通过对 GRU 时间序列模型的介绍,探讨Stacked GRU在股市科技股中的表现。本研究文章的结构如下。第一节介绍金融时间序列数据。第二节对金融时间数进行特征工程。第三节是构建模型、定义参数空间、损失函数与优化器。第四节是训练模型。第五节是评估模型与结果可视化。第六部分是预测下一个时间点的收盘价。

GRU 单变量时间序列预测

  • 1. 金融时间序列数据
    • 1.1 数据预处理
    • 1.2 探索性分析(可视化)
      • 1.2.1 股票的日收盘价
      • 1.2.2 股票的日收益率
      • 1.2.3 股票收益率自相关性
  • 2. 时间数据特征工程(APPL)
    • 2.1 构造序列数据
    • 2.2 特征缩放(归一化)
    • 2.3 数据集划分(TimeSeriesSplit)
    • 2.4 数据集张量(TensorDataset)
  • 3. 构建时间序列模型(Stacked GRU)
    • 3.1 构建 GRU 模型
    • 3.2 定义模型、损失函数与优化器
  • 4. 模型训练与可视化
  • 5. 模型评估与可视化
    • 5.1 均方误差
    • 5.2 反归一化
    • 5.3 结果可视化
  • 6. 模型预测
    • 6.1 转换最新时间步收盘价的数组为张量
    • 6.2 预测下一个时间点的收盘价格

1. 金融时间序列数据

金融时间序列数据是指按照时间顺序记录的各种金融指标的数值序列,这些指标包括但不限于股票价格、汇率、利率等。这些数据具有以下几个显著特点:

  1. 时间连续性:数据按照时间的先后顺序排列,反映了金融市场的动态变化过程。
  2. 噪声和不确定性:金融市场受到多种复杂因素的影响,因此数据中存在大量噪声和不确定性。
  3. 非线性和非平稳性:金融时间序列数据通常呈现出明显的非线性和非平稳性特征。
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

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 探索性分析(可视化)

探索性数据分析 E D A EDA EDA 是一种使用视觉技术分析数据的方法。它用于发现趋势和模式,或借助统计摘要和图形表示来检查假设。

1.2.1 股票的日收盘价

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

# plt.style.available
plt.style.use('seaborn-v0_8')
# 绘制收盘价
plt.figure(figsize=(18, 6))
plt.plot(AAPL['Adj Close'], label='AAPL')# 设置图表标题和轴标签
plt.title('Close Price with Moving Averages')
plt.xlabel('')
plt.ylabel('Price $', fontsize=18)# 显示图例
plt.legend()
plt.show()

请添加图片描述

1.2.2 股票的日收益率

股票的日收益率是反映投资者在一天内从股票投资中获得的回报比例。它通常用百分比来表示,计算公式为:日收益率 = (今日收盘价 - 前一日收盘价) / 前一日收盘价 × 100%,这里我们可是使用 .pct_change() 函数来实现。

plt.figure(figsize=(18,6))
plt.title('Daily Return History')
plt.plot(AAPL['Adj Close'].pct_change(),linestyle='--',marker='*',label='AAPL')
plt.ylabel('Daily Return', fontsize=18)
plt.legend()
plt.show()

请添加图片描述

1.2.3 股票收益率自相关性

股票收益率自相关性是描述一个股票在不同时间点的收益率如何相互关联的一个概念。具体来说,它指的是一个股票过去的收益率与其未来收益率之间的相关性。这种相关性可以是正相关(即过去的收益率上升预示着未来的收益率也可能上升),也可以是负相关(即过去的收益率上升预示着未来的收益率可能下降),或者两者之间没有显著的相关性。

AAPL['Returns'] = AAPL['Adj Close'].pct_change()# 使用pandas的autocorr函数计算自相关系数
# 注意:autocorr默认计算的是滞后1的自相关系数,要计算其他滞后的,需要循环或使用其他方法
autocorr_values = [AAPL['Returns'].autocorr(lag=i) for i in range(1, 301)]  # 假设我们查看滞后1到300的自相关# 使用matplotlib绘制自相关系数
plt.figure(figsize=(18, 6))
plt.plot(range(1, 301), autocorr_values, linestyle='-.', marker='*')
plt.title('Autocorrelation of Stock Returns')
plt.xlabel('Lag')
plt.ylabel('Autocorrelation')
plt.grid(True)
plt.show()

请添加图片描述

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

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

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

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

2.1 构造序列数据

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

# 构造序列数据函数
def create_dataset(dataset, lookback=1):"""Transform a time series into a prediction datasetArgs:dataset: A numpy array of time series, first dimension is the time stepslookback: Size of window for prediction"""X, y = [], []for i in range(len(dataset)-lookback): feature = dataset[i:(i+lookback), 0]target = dataset[i + lookback, 0]X.append(feature)y.append(target)return np.array(X), np.array(y)

2.2 特征缩放(归一化)

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

# 选取AAPL['Close']作为特征, 归一化数据
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(AAPL['Close'].values.reshape(-1, 1))
# 创建数据集
X, y = create_dataset(scaled_data, lookback=window_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_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, 1) (90, 60, 1) (605,) (90,)

2.4 数据集张量(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() 函数,允许我们重组数据,以匹配 LSTM 模型所需的输入形状。以这种方式重塑数据可确保 LSTM 模型以预期格式接收数据。

torch.Size([605, 60, 1]) torch.Size([90, 60, 1]) 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. 构建时间序列模型(Stacked GRU)

GRU (Gated Recurrent Unit)是一种循环神经网络 R N N RNN RNN的变体,用于处理和预测序列数据。与标准RNN相比,GRU能够更有效地捕捉长期依赖关系,并且在训练时更不容易出现梯度消失或梯度爆炸的问题。

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

Apply a multi-layer gated recurrent unit (GRU) RNN to an input sequence. For each element in the input sequence, each layer computes the following function:
r t = σ ( W i r x t + b i r + W h r h ( t − 1 ) + b h r ) z t = σ ( W i z x t + b i z + W h z h ( t − 1 ) + b h z ) n t = tanh ⁡ ( W i n x t + b i n + r t ⊙ ( W h n h ( t − 1 ) + b h n ) ) h t = ( 1 − z t ) ⊙ n t + z t ⊙ h ( t − 1 ) \begin{array}{ll} r_t = \sigma(W_{ir} x_t + b_{ir} + W_{hr} h_{(t-1)} + b_{hr}) \\ z_t = \sigma(W_{iz} x_t + b_{iz} + W_{hz} h_{(t-1)} + b_{hz}) \\ n_t = \tanh(W_{in} x_t + b_{in} + r_t \odot (W_{hn} h_{(t-1)}+ b_{hn})) \\ h_t = (1 - z_t) \odot n_t + z_t \odot h_{(t-1)} \end{array} rt=σ(Wirxt+bir+Whrh(t1)+bhr)zt=σ(Wizxt+biz+Whzh(t1)+bhz)nt=tanh(Winxt+bin+rt(Whnh(t1)+bhn))ht=(1zt)nt+zth(t1)
where h t h_t ht is the hidden 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)} h(t1) 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 r t r_t rt, z t z_t zt, n t n_t nt are the reset, update, and new gates, respectively. σ \sigma σ is the sigmoid function, and ⊙ \odot is the Hadamard product.

In a multilayer GRU, 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.

3.1 构建 GRU 模型

class GRUNet(nn.Module):def __init__(self, input_dim, hidden_dim, output_dim=1, num_layers=2):# input_dim 是输入特征的维度,hidden_dim 是隐藏层神经单元维度或称为隐藏状态的大小,output_dim 是输出维度,# num_layers 是网络层数,设置 num_layers=2 表示将两个 GRU 堆叠在一起形成一个堆叠 GRU,第二个 GRU 接收第一个 GRU 的输出并计算最终结果super(GRUNet, self).__init__()# 通过调用 super(GRUNet, self).__init__() 初始化父类 nn.Moduleself.hidden_dim = hidden_dimself.num_layers = num_layersself.gru = nn.GRU(input_dim, hidden_dim, num_layers, batch_first=True)# 定义 GRU 层,使用 batch_first=True 表示输入数据的形状是 [batch_size, seq_len(time_steps), input_dim]self.fc = nn.Linear(hidden_dim, output_dim)# 定义全连接层,将 GRU 的最后一个隐藏状态映射到输出维度 output_dimdef forward(self, x):h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).to(x.device)# 初始化h0为全零张量,h0代表隐藏状态(hidden state)的初始值,形状为 [num_layers * num_directions, batch, hidden_dim]# 如果没有指定双向参数 bidirectional为 True,num_directions 默认为 1out, _ = self.gru(x, h0)# 将输入数据 x 和初始隐藏状态 h0 传递给 GRU层,得到输出 out(即所有时间步的输出)和最后一个时间步的隐藏状态 hn(这里用 _忽略)out = self.fc(out[:, -1, :])# GRU 的输出是一个三维张量,其形状是 [batch_size, seq_len(time_steps), hidden_dim],# 这里我们只取最后一个时间步的隐藏状态 out[:, -1, :] 并传递给全连接层。return out

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

要在 PyTorch 中构建堆叠 GRU,我们需要调用 GRUNet 类,通过输入 num_layers 的参数来实现

model = GRUNet(input_dim=1, # 输入数据的特征数量 X_train.shape[2]hidden_dim=64,output_dim=1,num_layers=2) # 表示将两个 GRU 堆叠在一起形成一个堆叠 GRU
criterion = torch.nn.MSELoss() # 定义均方误差损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 定义优化器
summary(model, (32, 60, 1)) # batch_size, seq_len(time_steps), input_dim
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
GRUNet                                   [32, 1]                   --
├─GRU: 1-1                               [32, 60, 64]              37,824
├─Linear: 1-2                            [32, 1]                   65
==========================================================================================
Total params: 37,889
Trainable params: 37,889
Non-trainable params: 0
Total mult-adds (Units.MEGABYTES): 72.62
==========================================================================================
Input size (MB): 0.01
Forward/backward pass size (MB): 0.98
Params size (MB): 0.15
Estimated Total Size (MB): 1.14
==========================================================================================

4. 模型训练与可视化

train_loss = []
num_epochs = 20for epoch in range(num_epochs):model.train()  # 初始化训练进程pbar = tqdm(train_loader, desc=f"Epoch {epoch+1}/{num_epochs}")for batch_idx, (data, target) in enumerate(pbar):# 前向传播outputs = model(data)  # 每个批次的预测值loss = criterion(outputs, target)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()# 记录损失值train_loss.append(loss.item())# 更新进度条pbar.update()# 这里只用于显示当前批次的损失,不是平均损失pbar.set_postfix({'Train loss': f'{loss.item():.4f}'})

这里我们使用 tqdm模块来展示进度条

Epoch 1/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.25it/s, Train loss=0.0211]
Epoch 2/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0052]
Epoch 3/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.24it/s, Train loss=0.0030]
Epoch 4/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.06it/s, Train loss=0.0014]
Epoch 5/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.19it/s, Train loss=0.0011]
Epoch 6/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.21it/s, Train loss=0.0007]
Epoch 7/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.21it/s, Train loss=0.0015]
Epoch 8/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.22it/s, Train loss=0.0015]
Epoch 9/20: 100%|███████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.21it/s, Train loss=0.0012]
Epoch 10/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0010]
Epoch 11/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0014]
Epoch 12/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.19it/s, Train loss=0.0011]
Epoch 13/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.21it/s, Train loss=0.0013]
Epoch 14/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0013]
Epoch 15/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.03it/s, Train loss=0.0020]
Epoch 16/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.08it/s, Train loss=0.0012]
Epoch 17/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0009]
Epoch 18/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.22it/s, Train loss=0.0014]
Epoch 19/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.07it/s, Train loss=0.0019]
Epoch 20/20: 100%|██████████████████████████████████████████████████| 19/19 [00:01<00:00, 13.11it/s, Train loss=0.0013]
plt.plot(train_loss)

请添加图片描述

5. 模型评估与可视化

5.1 均方误差

model.eval()  # 将模型设置为评估模式
test_loss = []  # 初始化损失
pbar = tqdm(test_loader, desc="Evaluating")
with torch.no_grad():for data, target in pbar:test_pred = model(data)loss = criterion(test_pred, target)test_loss.append(loss.item())# 计算当前批次的平均损失batch_avg_loss = sum(test_loss)/len(test_loss)pbar.set_postfix({'Test Loss': f'{batch_avg_loss:.4f}'})pbar.update()  # 更新进度条pbar.close()  # 关闭进度条
Evaluating: 100%|██████████████████████████████████████████████████████| 3/3 [00:00<00:00, 51.30it/s, Test Loss=0.0011]

5.2 反归一化

.inverse_transform 将经过转换或缩放的数据转换回其原始形式或接近原始形式

# 反归一化预测结果
train_pred = scaler.inverse_transform(model(X_train_tensor).detach().numpy())
y_train = scaler.inverse_transform(y_train_tensor.detach().numpy())
test_pred = scaler.inverse_transform(model(X_test_tensor).detach().numpy())
y_test = scaler.inverse_transform(y_test_tensor.detach().numpy())print(train_pred.shape, y_train.shape, test_pred.shape, y_test.shape)
(605, 1) (605, 1) (90, 1) (90, 1)

5.3 结果可视化

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

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

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

# Visualize the data
plt.figure(figsize=(18,6))
plt.title('GRU 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['Close'][-window_size:].values
latest_closes = latest_closes.reshape(-1, 1)
scaled_latest_closes = scaler.fit_transform(latest_closes)
tensor_latest_closes = torch.from_numpy(scaled_latest_closes).type(torch.Tensor).view(1, window_size, 1)
print(tensor_latest_closes.shape)
torch.Size([1, 60, 1])

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

# 使用模型预测下一个时间点的收盘价
next_close_pred = model(tensor_latest_closes)
next_close_pred = scaler.inverse_transform(next_close_pred.detach().numpy())
next_close_pred
array([[166.83992]], dtype=float32)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

# 昇思25天学习打卡营第10天 | 使用静态图加速

昇思25天学习打卡营第10天 | 使用静态图加速 文章目录 昇思25天学习打卡营第10天 | 使用静态图加速动态图的开启方式静态图的开启方式基于全局context的开启方式基于修饰器的开启方式 总结打卡 AI编译框架分为两种运行模式&#xff1a; 动态图模式&#xff1a; 计算图的构建和计…

读人工智能全传07智能体

1. 布鲁克斯革命 1.1. 随着科学认知的发展&#xff0c;有时候旧有科学体系会面临全盘崩溃的危机&#xff0c;新的科学体系诞生&#xff0c;取代传统的、既定的科学体系&#xff0c;这就意味着科学的范式将发生变化 1.2. 澳大利亚机器人学家罗德尼布鲁克斯(Rodney Brooks)&…

DS1302实时时钟芯片_读写时间实现电子钟功能

一、前言 1.1 功能说明 本项目以STC90C51单片机为核心&#xff0c;结合DS1302实时时钟芯片和IIC协议的OLED显示屏&#xff0c;设计了一款功能丰富、操作简便的电子时钟。 【1】项目目标 实现高精度的时间显示&#xff0c;包括时、分、秒。提供按键调整时间的功能&#xff0…

[Java]Swing版坦克大战小游戏项目开发(1)——new出一个窗口

highlight: xcode theme: vuepress 前言 本系列文章带领 Java 初学者学习使用 Java 语言结合 Swing 技术以及设计模式开发一款经典小游戏——坦克大战。通过这个小游戏&#xff0c;你可以学会很多实用的设计模式思想&#xff0c;并且提高你的编码水平。 熟悉Frame Frame 类是 J…

【java计算机毕设】基于java的奶茶店管理系统的设计与实现MySQL ssm JSP maven项目代码源码+文档

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】奶茶店管理系统java MySQL ssm JSP maven项目源码代码万字文档 小组设计 2项目介绍 系统功能&#xff1a; 奶茶店管理系统包括管理员、用户俩种角色。 管理员功能包括个人中心模块用于修改个人信息和密码、…

UDP通讯实现

服务器端&#xff1a; 1.获取套接字 int fd;fdsocket(AF_INET,SOCK_DGRAM,0);if(fd<0){perror("socket");exit(0);} #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); -domain: 指定通信域&…

Retrofit框架源码深度剖析【Android热门框架分析第二弹】

Android热门框架解析&#xff0c;你确定不来看看吗&#xff1f; OkHttp框架源码深度剖析【Android热门框架分析第一弹】 Retrofit框架源码深度剖析【Android热门框架分析第二弹】 什么是Retrofit&#xff1f; 准确来说&#xff0c;Retrofit 是一个 RESTful 的 HTTP 网络请求…

Miniconda的常见用法——以Isaacgym为例

1. ubuntu24.04安装minicondda mkdir -p ~/miniconda3 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh解释下这段代码 bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3~/miniconda3/miniconda.sh: 指向Mi…

SHARPNESS-AWARE MINIMIZATION FOR EFFICIENTLY IMPROVING GENERALIZATION--论文笔记

论文笔记 资料 1.代码地址 https://github.com/google-research/sam https://github.com/davda54/sam 2.论文地址 https://arxiv.org/abs/2010.01412 3.数据集地址 论文摘要的翻译 在当今严重过度参数化的模型中&#xff0c;训练损失的值很难保证模型的泛化能力。事实上…

MySQL第三次练习

作业三 一 先创建DB abc&#xff0c;创建table student 1、插入一条记录 2、添加多条记录 3、添加部分记录 4、加0.5 5、删除成绩为空的记录 二 1、创建一个用户test1使他只能本地登录拥有查询student表的权限。 2、查询用户test1的权限。 3、删除用户test1. 全在一张图上…

怎样优化 PostgreSQL 中对日期时间范围的模糊查询?

文章目录 一、问题分析&#xff08;一&#xff09;索引未有效利用&#xff08;二&#xff09;日期时间格式不统一&#xff08;三&#xff09;复杂的查询条件 二、优化策略&#xff08;一&#xff09;使用合适的索引&#xff08;二&#xff09;规范日期时间格式&#xff08;三&a…

逻辑回归模型(非回归问题,而是分类问题)

目录&#xff1a; 一、Sigmoid函数&#xff1a;二、逻辑回归介绍&#xff1a;三、决策边界四、逻辑回归模型训练过程&#xff1a;1.训练目标&#xff1a;2.梯度下降调整参数&#xff1a; 一、Sigmoid函数&#xff1a; Sigmoid函数是构建逻辑回归模型的重要函数&#xff0c;如下…

免费压缩pdf文件大小软件收费吗?pdf如何压缩文件大小?12款压缩应用推荐!

在数字化时代&#xff0c;PDF文件因其跨平台、格式统一的特点而广受欢迎。然而&#xff0c;随着文件内容的增加&#xff0c;PDF文件的大小也逐渐增大&#xff0c;给存储和传输带来了诸多不便。因此&#xff0c;寻找一款合适的PDF压缩软件成为了许多用户的需求。本文将详细介绍1…

电子设备常用的胶水有哪些?

目录 1、502胶水 2、703胶水 3、704胶水 4、AB胶 5、红胶 6、Underfill 7、导电胶 8、UV胶 9、热熔胶 10、环氧树脂胶 11、硅酮胶 12、聚氨酯胶 13、丙烯酸胶 14、丁基胶 1、502胶水 502胶水&#xff0c;也被称为瞬间胶或快干胶&#xff0c;是一种非常常见的粘合…

电动卡丁车语音芯片方案选型:让驾驶体验更智能、更安全

在追求速度与激情的电动卡丁车领域&#xff0c;每一次升级都意味着更加极致的驾驶体验。而今天&#xff0c;我们要介绍的&#xff0c;正是一款能够显著提升电动卡丁车智能化与安全性的语音芯片方案——为您的爱车增添一份独特的魅力与安全保障。 智能化升级&#xff0c;从“听…

布隆过滤器 redis

一.为什么要用到布隆过滤器&#xff1f; 缓存穿透&#xff1a;查询一条不存在的数据&#xff0c;缓存中没有&#xff0c;则每次请求都打到数据库中&#xff0c;导致数据库瞬时请求压力过大&#xff0c;多见于爬虫恶性攻击因为布隆过滤器是二进制的数组&#xff0c;如果使用了它…

科普文:K8S中常见知识点梳理

简单说一下k8s集群内外网络如何互通的 要在 Kubernetes&#xff08;k8s&#xff09;集群内外建立网络互通&#xff0c;可以采取以下措施&#xff1a; 使用service&#xff1a; 使用Service类型为NodePort或LoadBalancer的Kubernetes服务。这可以使服务具有一个公共IP地址或端口…

Open3D 计算点云的平均密度

目录 一、概述 1.1基于领域密度计算原理 1.2应用 二、代码实现 三、实现效果 2.1点云显示 2.2密度计算结果 一、概述 在点云处理中&#xff0c;点的密度通常表示为某个点周围一定区域内的点的数量。高密度区域表示点云较密集&#xff0c;低密度区域表示点云较稀疏。计算…

Redis连接Resp图形化工具和springboot

Redis连接Resp图形化工具和springboot 1.redis配置1.1 备份、修改conf文件1.2 Redis的其它常见配置&#xff1a;1.3 启动Redis&#xff1a;1.4 停止服务&#xff1a;1.5 开机自启&#xff1a; 2. resp的安装、配置和连接&#xff1a;2.1 GitHub上下载2.2 开始连接redis ![在这里…