Jena Climate时间序列数据集上使用LSTM进行温度的预报

0. 项目背景

PaddleTS是一个易用的深度时序建模的Python库,它基于飞桨深度学习框架PaddlePaddle,专注业界领先的深度模型,旨在为领域专家和行业用户提供可扩展的时序建模能力和便捷易用的用户体验。PaddleTS的主要特性包括:

  • 设计统一数据结构,实现对多样化时序数据的表达,支持单目标与多目标变量,支持多类型协变量

  • 封装基础模型功能,如数据加载、回调设置、损失函数、训练过程控制等公共方法,帮助开发者在新模型开发过程中专注于网络结构本身

  • 内置业界领先的深度学习模型,例如NBEATS、NHiTS、LSTNet、TCN、Transformer 等

  • 内置经典数据转换算子,支持数据处理与转换,包括缺失值填充、异常值处理、归一化、时间相关的协变量提取等

  • 内置时序数据分析算子,帮助开发者便捷实现数据探索,包括数据统计量信息及数据摘要等功能

  • 支持自动超参寻优,自动、高效满足效果调优需求

在本项目中,我们就通过一个典型示例,介绍如何在实际场景应用PaddleTS。

1. 简要介绍

在本项目中,我们将使用深度时序建模库PaddleTS,在Jena Climate时间序列数据集上基于LSTM进行温度的预报。

2. 环境设置

# 安装paddlets依赖库 
!pip install paddlets
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import paddlets
from paddlets import TSDataset
from paddlets import TimeSeries
from paddlets.models.forecasting import MLPRegressor, LSTNetRegressor
from paddlets.transform import Fill, StandardScaler
from paddlets.metrics import MSE, MAE

3. 数据集

我们将使用的Jena Climate数据集来自 Max Planck Institute for Biogeochemistry. 该数据集包括温度、压力、湿度等14个特征指标,每10分钟记录一次。

记录地点: Weather Station, Max Planck Institute for Biogeochemistry in Jena, Germany

记录时间: 2009.01.19 - 2016.12.31

下表包括了数据列名、对应数据值以及他们的描述,主要就是一些气象单位的记录。

索引特征数值描述
1Date Time01.01.2009 00:10:00Date-time reference
2p (mbar)996.52The pascal SI derived unit of pressure used to quantify internal pressure. Meteorological reports typically state atmospheric pressure in millibars.
3T (degC)-8.02Temperature in Celsius
4Tpot (K)265.4Temperature in Kelvin
5Tdew (degC)-8.9Temperature in Celsius relative to humidity. Dew Point is a measure of the absolute amount of water in the air, the DP is the temperature at which the air cannot hold all the moisture in it and water condenses.
6rh (%)93.3Relative Humidity is a measure of how saturated the air is with water vapor, the %RH determines the amount of water contained within collection objects.
7VPmax (mbar)3.33Saturation vapor pressure
8VPact (mbar)3.11Vapor pressure
9VPdef (mbar)0.22Vapor pressure deficit
10sh (g/kg)1.94Specific humidity
11H2OC (mmol/mol)3.12Water vapor concentration
12rho (g/m ** 3)1307.75Airtight
13wv (m/s)1.03Wind speed
14max. wv (m/s)1.75Maximum wind speed
15wd (deg)152.3Wind direction in degrees

我们可以直接下载数据集到本地。

# 命令行执行
!wget https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip
# 解压数据集
!unzip jena_climate_2009_2016.csv.zip
--2022-10-27 08:57:36--  https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip
正在解析主机 storage.googleapis.com (storage.googleapis.com)... 172.217.160.80, 172.217.160.112, 172.217.163.48, ...
正在连接 storage.googleapis.com (storage.googleapis.com)|172.217.160.80|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 13568290 (13M) [application/zip]
正在保存至: “jena_climate_2009_2016.csv.zip”

jena_climate_2009_2 100%[===================>]  12.94M  20.4MB/s    in 0.6s    

2022-10-27 08:57:38 (20.4 MB/s) - 已保存 “jena_climate_2009_2016.csv.zip” [13568290/13568290])

Archive:  jena_climate_2009_2016.csv.zip
  inflating: jena_climate_2009_2016.csv  

加载并查看数据集。

csv_path = "jena_climate_2009_2016.csv"
df = pd.read_csv(csv_path)
df.head()
Date Timep (mbar)T (degC)Tpot (K)Tdew (degC)rh (%)VPmax (mbar)VPact (mbar)VPdef (mbar)sh (g/kg)H2OC (mmol/mol)rho (g/m**3)wv (m/s)max. wv (m/s)wd (deg)
001.01.2009 00:10:00996.52-8.02265.40-8.9093.33.333.110.221.943.121307.751.031.75152.3
101.01.2009 00:20:00996.57-8.41265.01-9.2893.43.233.020.211.893.031309.800.721.50136.1
201.01.2009 00:30:00996.53-8.51264.91-9.3193.93.213.010.201.883.021310.240.190.63171.6
301.01.2009 00:40:00996.51-8.31265.12-9.0794.23.263.070.191.923.081309.190.340.50198.0
401.01.2009 00:50:00996.51-8.27265.15-9.0494.13.273.080.191.923.091309.000.320.63214.3

为了让我们了解正在处理的数据,下面绘制了每个指标从2009年到2016年期间每个特征的时间序列趋势。从中我们可以发现存在异常的事件,可以在后续处理中进行关注。

titles = [
    "Pressure",
    "Temperature",
    "Temperature in Kelvin",
    "Temperature (dew point)",
    "Relative Humidity",
    "Saturation vapor pressure",
    "Vapor pressure",
    "Vapor pressure deficit",
    "Specific humidity",
    "Water vapor concentration",
    "Airtight",
    "Wind speed",
    "Maximum wind speed",
    "Wind direction in degrees",
]

feature_keys = [
    "p (mbar)",
    "T (degC)",
    "Tpot (K)",
    "Tdew (degC)",
    "rh (%)",
    "VPmax (mbar)",
    "VPact (mbar)",
    "VPdef (mbar)",
    "sh (g/kg)",
    "H2OC (mmol/mol)",
    "rho (g/m**3)",
    "wv (m/s)",
    "max. wv (m/s)",
    "wd (deg)",
]

colors = [
    "blue",
    "orange",
    "green",
    "red",
    "purple",
    "brown",
    "pink",
    "gray",
    "olive",
    "cyan",
]

date_time_key = "Date Time"


def show_raw_visualization(data):
    time_data = data[date_time_key]
    fig, axes = plt.subplots(
        nrows=7, ncols=2, figsize=(15, 20), dpi=80, facecolor="w", edgecolor="k"
    )
    for i in range(len(feature_keys)):
        key = feature_keys[i]
        c = colors[i % (len(colors))]
        t_data = data[key]
        t_data.index = time_data
        t_data.head()
        ax = t_data.plot(
            ax=axes[i // 2, i % 2],
            color=c,
            title="{} - {}".format(titles[i], key),
            rot=25,
        )
        ax.legend([titles[i]])
    plt.tight_layout()


show_raw_visualization(df)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/pandas/plotting/_matplotlib/tools.py:331: MatplotlibDeprecationWarning: 
The is_first_col function was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use ax.get_subplotspec().is_first_col() instead.
  if ax.is_first_col():

在这里插入图片描述

分析不同指标之间的相关性情况如下:

def show_heatmap(data):
    plt.matshow(data.corr())
    plt.xticks(range(data.shape[1]), data.columns, fontsize=14, rotation=90)
    plt.gca().xaxis.tick_bottom()
    plt.yticks(range(data.shape[1]), data.columns, fontsize=14)

    cb = plt.colorbar()
    cb.ax.tick_params(labelsize=14)
    plt.title("Feature Correlation Heatmap", fontsize=14)
    plt.show()


show_heatmap(df)

在这里插入图片描述

从相关性分析热力图中,我们可以看到部分指标之间有非常强的相关型,因此, 我们可以只选取其中一部分指标(相关性高的只保留1个)。

print(
    "选取的参数指标是:",
    ", ".join([titles[i] for i in [0, 1, 5, 7, 8, 10, 11]]),
)
selected_features = [feature_keys[i] for i in [0, 1, 5, 7, 8, 10, 11]]
features = df[selected_features]
features.index = df[date_time_key]
features.head()
选取的参数指标是: Pressure, Temperature, Saturation vapor pressure, Vapor pressure deficit, Specific humidity, Airtight, Wind speed
p (mbar)T (degC)VPmax (mbar)VPdef (mbar)sh (g/kg)rho (g/m**3)wv (m/s)
Date Time
01.01.2009 00:10:00996.52-8.023.330.221.941307.751.03
01.01.2009 00:20:00996.57-8.413.230.211.891309.800.72
01.01.2009 00:30:00996.53-8.513.210.201.881310.240.19
01.01.2009 00:40:00996.51-8.313.260.191.921309.190.34
01.01.2009 00:50:00996.51-8.273.270.191.921309.000.32
# 原始数据集存在重复项,要进行去重
df.drop_duplicates(subset=["Date Time"],keep='first',inplace=True)

TSDatasetPaddleTS 中最主要的类之一,其被设计用来表示绝大多数时序样本数据。通常,时序数据可以分为以下几种:

  1. 单变量数据,只包含单列的预测目标,同时可以包涵单列或者多列协变量

  2. 多变量数据,包涵多列预测目标,同时可以包涵单列或者多列协变量

TSDataset 需要包含time_index属性,time_index支持 pandas.DatetimeIndexpandas.RangeIndex 两种类型。

本数据集是单变量数据,只包含单列的预测目标,但是包含了多列协变量。

在TSDataset构建时,我们可以通过自动填充功能实现缺失值的填充,目前支持7种填充方式:max, min, avg, median, pre, back, zero,本项目中,我们先使用前值填充。

target_cov_dataset = TSDataset.load_from_dataframe(
    df,
    time_col='Date Time',
    target_cols='T (degC)',
    observed_cov_cols=['p (mbar)', 'VPmax (mbar)', 'VPdef (mbar)', 'sh (g/kg)',
       'rho (g/m**3)', 'wv (m/s)'],
    freq='1h',
    fill_missing_dates=True,
    fillna_method='pre'
)
target_cov_dataset.plot(['T (degC)', 'p (mbar)', 'VPmax (mbar)', 'VPdef (mbar)', 'sh (g/kg)',
       'rho (g/m**3)', 'wv (m/s)'])
<AxesSubplot:xlabel='Date Time'>

在这里插入图片描述

通过调用 TSDataset.summary 方法即可实现对数据统计信息的查看。

target_cov_dataset.summary()
T (degC)p (mbar)VPmax (mbar)VPdef (mbar)sh (g/kg)rho (g/m**3)wv (m/s)
missing0.0000000.000000.0000000.0000000.0000000.0000000.000000
count70128.00000070128.0000070128.00000070128.00000070128.00000070128.00000070128.000000
mean9.441719989.2185513.5659564.0322586.0222551216.1044611.697043
std8.4164328.357987.7295054.8890812.65428939.94845565.430179
min-23.010000918.300000.9500000.0000000.5000001064.260000-9999.000000
25%3.357500984.210007.7700000.8600003.9200001187.5600000.990000
50%9.390000989.5900011.8000002.1800005.6000001213.8900001.750000
75%15.450000994.7200017.5800005.2800007.7900001242.7200002.850000
max37.1300001015.2900063.26000045.42000017.8500001393.26000028.490000

构建训练、验证以及测试数据集

train_dataset, val_test_dataset = target_cov_dataset.split(0.7)
val_dataset, test_dataset = val_test_dataset.split(0.5)
train_dataset.plot(add_data=[val_dataset,test_dataset], labels=['Val', 'Test'])
<AxesSubplot:xlabel='Date Time'>

在这里插入图片描述

数据处理时,也通过将指定列的值缩放为零均值和单位方差来实现归一化转换。

# scaler = StandardScaler()
# scaler.fit(train_dataset)
# train_dataset_scaled = scaler.transform(train_dataset)
# val_test_dataset_scaled = scaler.transform(val_test_dataset)
# val_dataset_scaled = scaler.transform(val_dataset)
# test_dataset_scaled = scaler.transform(test_dataset)

4. 模型组网

PaddleTS 提供了开箱即用的时序深度学习模型。下面以LSTM为例,完成模型组网。

?LSTNetRegressor

预定义的LSTM模型输入参数

  • in_chunk_len (int) – 模型输入的时间序列长度.

  • out_chunk_len (int) – 模型输出的时间序列长度.

  • skip_chunk_len (int) – 可选变量, 输入序列与输出序列之间跳过的序列长度, 既不作为特征也不作为序测目标使用, 默认值为0

  • sampling_stride (int) – 相邻样本间的采样间隔.

  • loss_fn (Callable_[,_ paddle.Tensor_]__|_None) – 损失函数.

  • optimizer_fn (Callable_[,_ Optimizer_]_) – 优化算法.

  • optimizer_params (Dict_[str,_ Any_]_) – 优化器参数.

  • eval_metrics (List_[str]_) – 模型训练过程中的需要观测的评估指标.

  • callbacks (List_[Callback]_) – 自定义callback函数.

  • batch_size (int) – 训练数据或评估数据的批大小.

  • max_epochs (int) – 训练的最大轮数.

  • verbose (int) – 模型训练过程中打印日志信息的间隔.

  • patience (int) – 模型训练过程中, 当评估指标超过一定轮数不再变优,模型提前停止训练.

  • seed (int_|_None) – 全局随机数种子, 注: 保证每次模型参数初始化一致.

  • skip_size (int) – 递归跳跃组件(Skip RNN)用来捕获时间序列中的周期性所需的周期长度.

  • channels (int) – 第一层Conv1D的通道数量.

  • kernel_size (int) – 第一层Conv1D的卷积核大小.

  • rnn_cell_type (str) – RNN cell的类型, 支持GRU或LSTM.

  • rnn_num_cells (int) – RNN层中神经元的数量.

  • skip_rnn_cell_type (str) – Skip RNN cell的类型, 支持GRU或LSTM.

  • skip_rnn_num_cells (int) – Skip RNN层中神经元的数量.

  • dropout_rate (float) – 神经元丢弃概率.

  • output_activation (str_|_None) – 输出层的激活函数类型, 可以是None(无激活函数), sigmoid, tanh.

lstm = LSTNetRegressor(
    in_chunk_len = 10 * 72,
    out_chunk_len = 72,
    max_epochs=20
)

5. 模型训练

使用模型网络结构和数据集进行模型训练。越复杂的网络结构,模型训练耗时会更长。

lstm.fit(train_dataset, val_dataset)
[2022-10-27 11:30:53,357] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 000| loss: 35.368192| val_0_mae: 4.169073| 0:00:57s
[2022-10-27 11:31:50,509] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 001| loss: 29.431509| val_0_mae: 4.266434| 0:01:54s
[2022-10-27 11:32:46,456] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 002| loss: 28.848934| val_0_mae: 4.024090| 0:02:50s
[2022-10-27 11:33:42,994] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 003| loss: 28.228769| val_0_mae: 4.033281| 0:03:47s
[2022-10-27 11:34:39,495] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 004| loss: 27.997010| val_0_mae: 4.132756| 0:04:43s
[2022-10-27 11:35:35,922] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 005| loss: 28.030989| val_0_mae: 3.856824| 0:05:40s
[2022-10-27 11:36:32,006] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 006| loss: 27.850923| val_0_mae: 3.914844| 0:06:36s
[2022-10-27 11:37:28,180] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 007| loss: 27.666451| val_0_mae: 4.191470| 0:07:32s
[2022-10-27 11:38:24,365] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 008| loss: 27.540988| val_0_mae: 3.841269| 0:08:28s
[2022-10-27 11:39:20,311] [paddlets.models.common.callbacks.callbacks] [INFO] epoch 009| loss: 27.555906| val_0_mae: 3.866439| 0:09:24s
[2022-10-27 11:39:20,314] [paddlets.models.common.callbacks.callbacks] [INFO] Stop training because you reached max_epochs = 10 with best_epoch = 8 and best_val_0_mae = 3.841269
[2022-10-27 11:39:20,315] [paddlets.models.common.callbacks.callbacks] [INFO] Best weights from best epoch are automatically used!

6. 模型评估

评估指标(Metric)用来衡量一个模型的效果, 一般是通过计算模型的预测结果和真实结果之间的某种差距。

与损失函数类似, 不同的任务场景会选择不同的评估指标评估模型的效果, 例如 MAE(Mean Absolute Error) 和 MSE(Mean squared error) 常用于回归任务. PaddleTS库内置了常用的评估指标, 同时也支持开发者自定义评估指标。

# 查看PaddleTS库内置的评估指标
??paddlets.metrics
subset_test_pred_dataset = lstm.predict(val_dataset)
subset_test_dataset, _ = test_dataset.split(len(subset_test_pred_dataset.target))
mae = MAE()
mae(subset_test_dataset, subset_test_pred_dataset)
{'T (degC)': 2.9071375346183777}

7. 模型预测

对模型进行预测,展示效果。

subset_test_dataset, _ = test_dataset.split(len(subset_test_pred_dataset.target))
subset_test_dataset.plot(add_data=subset_test_pred_dataset, labels=['Pred'])
<AxesSubplot:xlabel='Date Time'>

在这里插入图片描述

8. 模型持久化

模型训练完成后,可以保存模型,并在需要的时候重新加载。

# save the model for multiple times.
lstm.save("lstm")
from paddlets.models.model_loader import load
loaded_lstm = load("lstm")
loaded_lstm.predict(val_dataset)
                     T (degC)
2015-10-20 17:10:00  9.508100
2015-10-20 18:10:00  9.905542
2015-10-20 19:10:00  7.696136
2015-10-20 20:10:00  7.473157
2015-10-20 21:10:00  6.958349
...                       ...
2015-10-23 12:10:00  7.958826
2015-10-23 13:10:00  8.481768
2015-10-23 14:10:00  8.703350
2015-10-23 15:10:00  9.129288
2015-10-23 16:10:00  9.459382

[72 rows x 1 columns]

此文章为搬运
原项目链接

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐