弱电网站源码营销型网站盈利方案
预测-双注意LSTM自动编码器
- 1 预测-双注意LSTM自动编码器
 - 1.1 复现环境配置
 - 1.2 数据流记录
 - 1.2.1 **构建Dataset**
 - (1) **`X` 的取数**
 - (2) **`y` 的取数**
 - (3) **`target` 的取数**
 
- 1.2.2 **举例说明**
 - (1)**`X` 的取数**
 - (2)**`y` 的取数**
 - (3)**`target` 的取数**
 
- 1.2.3 **`y` 取数的问题**
 - **修正后的代码**
 - 1.2.4 **总结**
 - 1.2.5 数据流总结:
 - 1.2.6 数据流图示:
 - 1.2.7 参考:
 
- 2 数据维度变化流程
 - 2.1 流程图
 - 2.2 总结
 
1 预测-双注意LSTM自动编码器
复现github链接:https://github.com/JulesBelveze/time-series-autoencoder.git
 论文:A Dual-Stage Attention-Based Recurrent Neural Network for Time Series Prediction:https://arxiv.org/abs/1704.02971
1.1 复现环境配置
python版本:python3.8.20
 cuda版本:cuda111
 包版本环境参考:
Package              Version      Editable project location
-------------------- ------------ ---------------------------
build                1.2.2.post1
CacheControl         0.14.2
certifi              2025.1.31
charset-normalizer   3.4.1
cleo                 2.1.0
colorama             0.4.6
contourpy            1.1.1
crashtest            0.4.1
cycler               0.10.0
distlib              0.3.9
dulwich              0.21.7
fastjsonschema       2.21.1
filelock             3.16.1
fonttools            4.56.0
future               0.18.2
idna                 3.10
importlib_metadata   8.5.0
importlib_resources  6.4.5
installer            0.7.0
jaraco.classes       3.4.0
joblib               0.15.1
keyring              24.3.1
kiwisolver           1.2.0
matplotlib           3.2.1
more-itertools       10.5.0
msgpack              1.1.0
numpy                1.21.0
packaging            24.2
pandas               1.1.5
pexpect              4.9.0
pillow               10.4.0
pip                  24.3.1
pkginfo              1.12.1.2
platformdirs         4.3.6
poetry               1.8.5
poetry-core          1.9.1
poetry-plugin-export 1.8.0
protobuf             5.29.3
ptyprocess           0.7.0
pyparsing            2.4.7
pyproject_hooks      1.2.0
python-dateutil      2.8.1
pytz                 2025.1
pywin32-ctypes       0.2.3
rapidfuzz            3.9.7
requests             2.32.3
requests-toolbelt    1.0.0
scikit-learn         0.23.1
scipy                1.4.1
setuptools           75.3.0
shellingham          1.5.4
six                  1.15.0
sklearn              0.0
tensorboardX         2.6.2.2
threadpoolctl        2.1.0
tomli                2.2.1
tomlkit              0.13.2
torch                1.9.1+cu111
torchaudio           0.9.1
torchvision          0.10.1+cu111
tqdm                 4.46.1
trove-classifiers    2025.2.18.16
tsa                  0.1.0        D:\temp\Pytorch双注意LSTM自动编码器
typing_extensions    4.12.2
urllib3              2.2.3
virtualenv           20.29.2
wheel                0.45.1
zipp                 3.20.2
 
注:
vscode配置:
{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "Python Debugger: Current File with Arguments","type": "debugpy","request": "launch","program": "${file}","cwd":"${fileDirname}","console": "integratedTerminal",// "args": [//     "--ckpt", "output/checkpoint-5000.ckpt"  // 添加 --ckpt 参数及其值// ]}]
}
 
1.2 数据流记录
源代码所用数据字段:
| 列名          | 含义               | 单位     |
| ------------- | ------------------ | -------- |
| Date_Time     | 日期和时间         | -        |
| CO(GT)        | 一氧化碳浓度       | mg/m³    |
| PT08.S1(CO)   | 一氧化碳传感器响应值 | 无量纲  |
| NMHC(GT)      | 非甲烷烃浓度       | µg/m³   |
| C6H6(GT)      | 苯浓度             | µg/m³   |
| PT08.S2(NMHC) | 非甲烷烃传感器响应值 | 无量纲 |
| NOx(GT)       | 氮氧化物浓度       | µg/m³   |
| PT08.S3(NOx)  | 氮氧化物传感器响应值 | 无量纲 |
| NO2(GT)       | 二氧化氮浓度       | µg/m³   |
| PT08.S4(NO2)  | 二氧化氮传感器响应值 | 无量纲 |
| PT08.S5(O3)   | 臭氧传感器响应值    | 无量纲  |
| T             | 温度               | °C      |
| RH            | 相对湿度           | %       |
| AH            | 绝对湿度           | g/m³    |
 
将时间序列数据转换为适合时间序列预测的格式,具体来说,它通过滑动窗口的方式从输入数据 X 和标签 y 中提取特征和标签,并生成一个 TensorDataset。提取特征和标签,预测的是后面的预测窗口长度的标签。下面我将详细解释 X、y 和 target 的取数逻辑,并指出 y 取数可能存在的问题。
1.2.1 构建Dataset
(1) X 的取数
 
X是输入特征数据,形状为(nb_obs, nb_features),其中nb_obs是样本数量,nb_features是特征数量。- 通过滑动窗口的方式,从 
X中提取长度为seq_length的序列:features.append(torch.FloatTensor(X[i:i + self.seq_length, :]).unsqueeze(0))- 例如,如果 
seq_length = 10,则每次提取X[i:i+10, :],即从第i个时间步开始的 10 个时间步的特征数据。 unsqueeze(0)是为了增加一个批次维度。
 - 例如,如果 
 
(2) y 的取数
 
y是目标值(标签),通常是与X对应的输出值。- 代码中从 
y中提取的是滞后一期的历史值(y[i-1:i+self.seq_length-1]):y_hist.append(torch.FloatTensor(y[i - 1:i + self.seq_length - 1]).unsqueeze(0))- 例如,如果 
seq_length = 10,则提取的是y[i-1:i+9],即从第i-1个时间步开始的 10 个时间步的标签值。 - 这里 
y[i-1]的使用可能有问题,因为y[i-1]是前一个时间步的值,而不是当前时间步的值。如果y是当前时间步的标签,那么这里应该直接使用y[i:i+self.seq_length]。 
 - 例如,如果 
 
(3) target 的取数
 
target是预测的目标值,即未来prediction_window个时间步的标签值:target.append(torch.FloatTensor(y[i + self.seq_length:i + self.seq_length + self.prediction_window]))- 例如,如果 
seq_length = 10且prediction_window = 5,则提取的是y[i+10:i+15],即从第i+10个时间步开始的 5 个时间步的标签值。 
- 例如,如果 
 
1.2.2 举例说明
假设有以下数据:
X和y的长度为 20。seq_length = 3,prediction_window = 2。
(1)X 的取数
 
- 当 
i = 1时,提取X[1:4, :]。 - 当 
i = 2时,提取X[2:5, :]。 - 以此类推。
 
(2)y 的取数
 
- 当 
i = 1时,提取y[0:3](即y[i-1:i+seq_length-1])。 - 当 
i = 2时,提取y[1:4]。 - 以此类推。
 
(3)target 的取数
 
- 当 
i = 1时,提取y[4:6](即y[i+seq_length:i+seq_length+prediction_window])。 - 当 
i = 2时,提取y[5:7]。 - 以此类推。
 
1.2.3 y 取数的问题
 
在代码中,y 的取数逻辑是:
y_hist.append(torch.FloatTensor(y[i - 1:i + self.seq_length - 1]).unsqueeze(0))
 
这里使用了 y[i-1],即前一个时间步的值。如果 y 是当前时间步的标签,那么这里应该直接使用 y[i:i+self.seq_length],而不是 y[i-1:i+self.seq_length-1]。修正后的代码应该是:
y_hist.append(torch.FloatTensor(y[i:i + self.seq_length]).unsqueeze(0))
 
修正后的代码
def frame_series(self, X, y=None):'''Function used to prepare the data for time series prediction:param X: set of features:param y: targeted value to predict:return: TensorDataset'''nb_obs, nb_features = X.shapefeatures, target, y_hist = [], [], []for i in range(1, nb_obs - self.seq_length - self.prediction_window):features.append(torch.FloatTensor(X[i:i + self.seq_length, :]).unsqueeze(0))# 修正后的 y 取数逻辑y_hist.append(torch.FloatTensor(y[i:i + self.seq_length]).unsqueeze(0))features_var, y_hist_var = torch.cat(features), torch.cat(y_hist)if y is not None:for i in range(1, nb_obs - self.seq_length - self.prediction_window):target.append(torch.FloatTensor(y[i + self.seq_length:i + self.seq_length + self.prediction_window]))target_var = torch.cat(target)return TensorDataset(features_var, y_hist_var, target_var)return TensorDataset(features_var)
 
1.2.4 总结
X的取数是滑动窗口提取特征序列。y的取数逻辑存在问题,不应使用y[i-1],而应直接使用y[i:i+self.seq_length]。target的取数是提取未来prediction_window个时间步的标签值。
这段代码的数据流可以分为以下几个步骤:
-  
数据预处理:
- 调用 
self.preprocess_data()方法,生成训练集和测试集的特征和标签:X_train,X_test,y_train,y_test。 - 从 
X_train中获取特征的数量nb_features。 
 - 调用 
 -  
数据集封装:
- 调用 
self.frame_series(X_train, y_train)方法,将训练集的特征和标签封装成一个train_dataset对象。 - 调用 
self.frame_series(X_test, y_test)方法,将测试集的特征和标签封装成一个test_dataset对象。 
 - 调用 
 -  
DataLoader 创建:
- 使用 
DataLoader类创建train_iter,用于加载训练数据集。参数包括batch_size(批次大小)、shuffle=False(不打乱数据)、drop_last=True(丢弃最后一个不完整的批次)。 - 使用 
DataLoader类创建test_iter,用于加载测试数据集。参数与train_iter相同。 
 - 使用 
 -  
返回结果:
- 返回 
train_iter(训练数据加载器)、test_iter(测试数据加载器)和nb_features(特征数量)。 
 - 返回 
 
1.2.5 数据流总结:
- 输入:原始数据通过 
self.preprocess_data()进行预处理,生成特征和标签。 - 处理:特征和标签被封装成 
Dataset对象,然后通过DataLoader进行批次加载。 - 输出:返回训练和测试的 
DataLoader对象,以及特征数量。 
1.2.6 数据流图示:
原始数据 → preprocess_data() → (X_train, X_test, y_train, y_test) → frame_series() → (train_dataset, test_dataset) → DataLoader() → (train_iter, test_iter)
 
1.2.7 参考:
DataLoader是 PyTorch 中用于批量加载数据的工具,支持多线程加载、数据打乱等功能。Dataset是 PyTorch 中用于封装数据集的基类,通常需要实现__len__和__getitem__方法。
为了更好地理解数据维度的变化情况,我们可以通过一个具体的例子来逐步分析代码中的数据维度变化。假设我们有一个时间序列数据集,包含以下列:
date: 时间戳feature1: 数值特征feature2: 数值特征category: 类别特征target: 目标值
2 数据维度变化流程
-  
原始数据 (
data):- 假设数据集有 1000 行,5 列(
date,feature1,feature2,category,target)。 - 维度:
(1000, 5) 
 - 假设数据集有 1000 行,5 列(
 -  
预处理 (
preprocess_data):X = data.drop('target', axis=1):去掉目标列,剩下 4 列。- 维度:
(1000, 4) 
- 维度:
 y = data['target']:目标列。- 维度:
(1000,) 
- 维度:
 X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, shuffle=False):X_train维度:(800, 4)X_test维度:(200, 4)y_train维度:(800,)y_test维度:(200,)
X_train = preprocessor.fit_transform(X_train):经过ColumnTransformer处理,假设category列被编码为 3 个新列。- 维度:
(800, 5)(feature1,feature2,category_encoded_1,category_encoded_2,category_encoded_3) 
- 维度:
 X_test = preprocessor.transform(X_test):- 维度:
(200, 5) 
- 维度:
 
 -  
时间序列帧化 (
frame_series):- 假设 
seq_length = 10,prediction_window = 1。 nb_obs, nb_features = X_train.shape:nb_obs = 800,nb_features = 5
features和y_hist的生成:- 对于 
i从 1 到800 - 10 - 1 = 789,每次取 10 个时间步的数据。 features维度:(789, 10, 5)y_hist维度:(789, 10)
- 对于 
 target的生成:- 对于 
i从 1 到789,每次取 1 个时间步的目标值。 target维度:(789, 1)
- 对于 
 TensorDataset的生成:features_var维度:(789, 10, 5)y_hist_var维度:(789, 10)target_var维度:(789, 1)
 - 假设 
 -  
DataLoader (
get_loaders):train_iter = DataLoader(train_dataset, batch_size=32, shuffle=False, drop_last=True):- 每个 batch 的维度:
(32, 10, 5)(特征),(32, 10)(历史目标),(32, 1)(目标) 
- 每个 batch 的维度:
 test_iter = DataLoader(test_dataset, batch_size=32, shuffle=False, drop_last=True):- 每个 batch 的维度:
(32, 10, 5)(特征),(32, 10)(历史目标),(32, 1)(目标) 
- 每个 batch 的维度:
 
 
2.1 流程图
原始数据 (1000, 5)|v
预处理 (X_train: 800, 5, y_train: 800)|v
时间序列帧化 (features: 789, 10, 5, y_hist: 789, 10, target: 789, 1)|v
DataLoader (batch_size=32, features: 32, 10, 5, y_hist: 32, 10, target: 32, 1)
 
2.2 总结
通过上述步骤,可以看到数据从原始形式逐步转换为适合时间序列模型训练的格式。每个步骤中的数据维度变化如下:
- 原始数据:
(1000, 5) - 预处理后:
(800, 5)(训练集特征),(800,)(训练集目标) - 时间序列帧化后:
(789, 10, 5)(特征),(789, 10)(历史目标),(789, 1)(目标) - DataLoader 中:
(32, 10, 5)(特征),(32, 10)(历史目标),(32, 1)(目标) 
