数值预测案例 LSTM 时间序列气温数据预测,附TensorFlow完整代码

Posted 立Sir

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数值预测案例 LSTM 时间序列气温数据预测,附TensorFlow完整代码相关的知识,希望对你有一定的参考价值。

大家好,今天和各位分享一下如何使用循环神经网络 LSTM 完成有多个特征的气温预测。上一节中我介绍了 LSTM 的单个特征的预测,感兴趣的可以看一下:https://blog.csdn.net/dgvv4/article/details/124349963


1. 导入工具包

我使用GPU加速计算,没有GPU的朋友可以把调用GPU的代码段去掉。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 调用GPU加速
gpus = tf.config.experimental.list_physical_devices(device_type='GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

2. 读取数据集

数据集地址:https://pan.baidu.com/s/1E5h-imMwdIyPv1Zc7FfC9Q   提取码:9cb5 

该数据集10分钟记录一次,有42w行数据,14列特征,选取除时间列以外的前10列特征用于本模型。使用pandas的绘图方法绘制特征随时间的变化曲线。

#(1)读取数据集
filepath = 'D:/deeplearning/test/神经网络/循环神经网络/climate.csv'
data = pd.read_csv(filepath)
print(data.head())  # 数据是10min记录一次的

#(2)特征选择
# 选择从第1列开始往后的所有行的数据
feat = data.iloc[:, 1:11]  # 最后4个特征列不要
date = data.iloc[:, 0]   # 获取时间信息

#(3)利用pandas绘图展示每个特征点分布情况
feat.plot(subplots=True, figsize=(80,10),  # 为每一列单独开辟子图,设置画板大小
          layout=(5,2), title='climate features')  # 14张图的排序方式,设置标题

数据集信息如下

绘制除时间特征DateTime列以外的后10列的特征数据的随时间变化的曲线


3. 数据预处理

由于数据量较大,全部用于训练可能会导致内存占用不足的报错,这里就取前2w个数据用于训练。求训练集中,每个特征列的均值和标准差对整个数据集使用训练集的均值和标准差进行标准化预处理以标准化后的气温数据作为标签

#(4)特征数据预处理
train_num = 20000  # 取前2w组数据用于训练
val_num = 23000  # 取2w-2.3w的数据用于验证
# 2.3w-2.5w的数据用于验证用于测试

# 求训练集的每个特征列的均值和标准差
feat_mean = feat[:train_num].mean(axis=0)
feat_std = feat[:train_num].std(axis=0)

# 对整个数据集计算标准差
feat = (feat - feat_mean) / feat_std

# 保存所有的气温数据,即标签数据
targets = feat.iloc[:,1]   # 取标准化之后的气温数据作为标签值

4. 时间序列函数提取特征和标签

通过一个滑动窗口在数据集上移动,例如使用当前10个特征的20行数据预测未来某一时间点/段的气温。任务要求使用连续5天的数据预测下一个时间点的气温值,数据是10min记录一次的。

对某一时间点的预测:五天一共有5*24*6=720个数据,窗口每次滑动一步,第一次滑动窗口范围 range(0, 720, 1),预测第720个气温。第二次滑动窗口范围 range(1,721,1),预测第721个气温。range()取值顾头不顾尾

对某一时间段的预测:由于数据集是10min记录一次的,两两数据行之间的差别很小,可以设置一个步长每隔60min取一次特征数据第一次滑动窗口范围 range(0, 720, 6)预测下一整天的每个小时的气温数据,即 range(720, 720+24*6, 6)。第二次滑动窗口范围 range(1,721,6),预测下一天的小时气温 range(721, 721+24*6, 6)

这里就预测某一时间点的数据,参数如下,可以自行修改

'''
dataset 代表特征数据
start_index 代表从数据的第几个索引值开始取
history_size 滑动窗口大小
end_index 代表数据取到哪个索引就结束
target_size 代表预测未来某一时间点还是时间段的气温。例如target_size=0代表用前20个特征预测第21个的气温
step 代表在滑动窗口中每隔多少步取一组特征
point_time 布尔类型,用来表示预测未来某一时间点的气温,还是时间段的气温
true 原始气温数据的所有标签值
'''

def TimeSeries(dataset, start_index, history_size, end_index, step,
               target_size, point_time, true):
    
    data = []  # 保存特征数据
    labels = []  # 保存特征数据对应的标签值
    
    start_index = start_index + history_size  # 第一次的取值范围[0:start_index]
    
    # 如果没有指定滑动窗口取到哪个结束,那就取到最后
    if end_index is None:
        # 数据集最后一块是用来作为标签值的,特征不能取到底
        end_index = len(dataset) - target_size
        
    # 滑动窗口的起始位置到终止位置每次移动一步
    for i in range(start_index, end_index):
        
        # 滑窗中的值不全部取出来用,每隔60min取一次
        index = range(i-history_size, i, step)  # 第一次相当于range(0, start_index, 6)
        
        # 根据索引取出所有的特征数据的指定行
        data.append(dataset.iloc[index])
        
        # 用这些特征来预测某一个时间点的值还是未来某一时间段的值
        if point_time is True:  # 预测某一个时间点
            # 预测未来哪个时间点的数据,例如[0:20]的特征数据(20取不到),来预测第20个的标签值
            labels.append(true[i+target_size])
        
        else:  # 预测未来某一时间区间
            # 例如[0:20]的特征数据(20取不到),来预测[20,20+target_size]数据区间的标签值
            labels.append(true[i:i+target_size])
    
    # 返回划分好了的时间序列特征及其对应的标签值
    return np.array(data), np.array(labels)

5. 划分数据集

使用上面的时间序列函数获取训练所需的特征值和标签值。这里以预测下一个时间点的气温值为例,history_size 指定时间序列窗口的大小,即用多少行数据来预测一个时间点的气温值;target_size 代表未来哪个时间点的值,为0代表,如range(0,720,1)的特征用来预测第720+0个时间点的气温值。point_time=False时代表预测某一时间段

#(6)划分数据集
history_size = 5*24*6  # 每个滑窗取5天的数据量=720
target_size =  0  # 预测未来下一个时间点的气温值
step = 1  # 步长为1取所有的行

# 构造训练集
x_train, y_train = TimeSeries(dataset=feat, start_index=0, history_size=history_size, end_index=train_num,
                              step=step, target_size=target_size, point_time=True, true=targets)

# 构造验证集
x_val, y_val = TimeSeries(dataset=feat, start_index=train_num, history_size=history_size, end_index=val_num,
                          step=step, target_size=target_size, point_time=True, true=targets)

# 构造测试集
x_test, y_test =  TimeSeries(dataset=feat, start_index=val_num, history_size=history_size, end_index=25000,
                              step=step, target_size=target_size, point_time=True, true=targets)

# 查看数据集信息
print('x_train_shape:', x_train.shape)  # (19280, 720, 10)
print('y_train_shape:', y_train.shape)  # (19280,)

6. 构造数据集

将划分好了的特征值和标签值转为tensor类型,对训练集的特征行随机打乱shuffle(),并且每次迭代时每个step训练batchsize=128组数据。设置迭代器 iter()从数据集中取出一个batch的数据 next()标签值y_train代表滑动窗口的每720行特征数据对应1个标签气温值

#(7)构造数据集
train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))  # 训练集
train_ds = train_ds.batch(128).shuffle(10000)  # 随机打乱、每个step处理128组数据

val_ds = tf.data.Dataset.from_tensor_slices((x_val, y_val))  # 验证集
val_ds = val_ds.batch(128)  

test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test))  # 测试集
test_ds = test_ds.batch(128)  

# 查看数据集信息
sample = next(iter(train_ds))  # 取出一个batch的数据
print('x_train.shape:', sample[0].shape)  # [128, 720, 10]
print('y_train.shape:', sample[1].shape)  # [128, ]

7. 模型构建

接下来就是自定义LSTM网络,这个无所谓想怎么搭都行,要注意的时 layers.LSTM() 层中有一个参数 return_sequences代表返回输出序列中的最后一个值,还是所有值。默认False一般是下一层还是 LSTM 的时候才用 return_sequences=True

#(8)模型构建
inputs_shape = sample[0].shape[1:]  # [120,10]  不需要写batch的维度大小
inputs = keras.Input(shape=inputs_shape)  # 输入层

# LSTM层,设置l2正则化
x = layers.LSTM(units=8, dropout=0.5, return_sequences=True, kernel_regularizer=tf.keras.regularizers.l2(0.01))(inputs)
x = layers.LeakyReLU()(x)
x = layers.LSTM(units=16, dropout=0.5, return_sequences=True, kernel_regularizer=tf.keras.regularizers.l2(0.01))(inputs)
x = layers.LeakyReLU()(x)
x = layers.LSTM(units=32, dropout=0.5, kernel_regularizer=tf.keras.regularizers.l2(0.01))(x)
x = layers.LeakyReLU()(x)
# 全连接层,随即正态分布的权重初始化,l2正则化
x = layers.Dense(64,kernel_initializer='random_normal',kernel_regularizer=tf.keras.regularizers.l2(0.01))(x)
x = layers.Dropout(0.5)(x)
# 输出层返回回归计算后的未来某一时间点的气温值
outputs = layers.Dense(1)(x)  # 标签shape要和网络shape一样

# 构建模型
model = keras.Model(inputs, outputs)

# 查看网络结构
model.summary()

网络结构如下

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_3 (InputLayer)         [(None, 720, 10)]         0         
_________________________________________________________________
lstm_7 (LSTM)                (None, 720, 16)           1728      
_________________________________________________________________
leaky_re_lu_7 (LeakyReLU)    (None, 720, 16)           0         
_________________________________________________________________
lstm_8 (LSTM)                (None, 32)                6272      
_________________________________________________________________
leaky_re_lu_8 (LeakyReLU)    (None, 32)                0         
_________________________________________________________________
dense_4 (Dense)              (None, 64)                2112      
_________________________________________________________________
dropout_2 (Dropout)          (None, 64)                0         
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 65        
=================================================================
Total params: 10,177
Trainable params: 10,177
Non-trainable params: 0
_________________________________________________________________

8.网络训练

使用平均绝对误差作为回归损失函数,训练完成后对整个测试集评估.evaluate(),计算整个测试集的损失。

# 网络编译
model.compile(optimizer = keras.optimizers.Adam(0.001),  # adam优化器学习率0.001
              loss = tf.keras.losses.MeanAbsoluteError())  # 计算标签和预测之间绝对差异的平均值
                          
epochs = 15  # 网络迭代次数

# 网络训练
history = model.fit(train_ds, epochs=epochs, validation_data=val_ds)

# 测试集评价
model.evaluate(test_ds)  # loss: 0.1212

训练过程如下:

Epoch 1/15
151/151 [==============================] - 11s 60ms/step - loss: 0.8529 - val_loss: 0.4423
Epoch 2/15
151/151 [==============================] - 9s 56ms/step - loss: 0.3999 - val_loss: 0.2660
------------------------------------------
------------------------------------------
Epoch 14/15
151/151 [==============================] - 9s 56ms/step - loss: 0.1879 - val_loss: 0.1442
Epoch 15/15
151/151 [==============================] - 9s 56ms/step - loss: 0.1831 - val_loss: 0.1254

9. 训练过程可视化

history 中保存了网络训练过程的所有指标,这里只使用了平均绝对误差损失,将损失指标随着每次迭代的变化曲线绘制出来。

#(10)查看训练信息
history_dict = history.history  # 获取训练的数据字典
train_loss = history_dict['loss']  # 训练集损失
val_loss = history_dict['val_loss']  # 验证集损失

#(11)绘制训练损失和验证损失
plt.figure()
plt.plot(range(epochs), train_loss, label='train_loss')  # 训练集损失
plt.plot(range(epochs), val_loss, label='val_loss')  # 验证集损失
plt.legend()  # 显示标签
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()


10. 预测阶段

为了绘图清晰,只对测试集的前200组特征(每一组有720行10列,720代表一个滑窗大小,10代表特征列个数)进行预测,使用.predict()函数 得到每组对应下一时刻的气温预测值。

#(12)预测阶段
# x_test[0].shape = (720,10)
x_predict = x_test[:200]  # 用测试集的前200组特征数据来预测 
y_true = y_test[:200]  # 每组特征对应的标签值

y_predict = model.predict(x_predict)  # 对测试集的特征预测

# 绘制标准化后的气温曲线图
fig = plt.figure(figsize=(10,5))  # 画板大小
axes = fig.add_subplot(111)  # 画板上添加一张图
# 真实值, date_test是对应的时间
axes.plot(y_true, 'bo', label='actual')
# 预测值,红色散点
axes.plot(y_predict, 'ro', label='predict')
 
plt.legend()  # 注释
plt.grid()  # 网格
plt.show()

预测值和真实值的对比如下

DL之LSTM/GRU/CNN:基于tensorflow框架分别利用LSTM/GRUCNN算法对上海最高气温实现回归预测案例

DL之LSTM/GRU/CNN:基于tensorflow框架分别利用LSTM/GRU、CNN算法对上海最高气温实现回归预测案例

目录

基于tensorflow框架分别利用LSTM/GRU、CNN算法对上海最高气温实现回归预测案例

# 1、定义数据集

# 2、特征工程

# 2.1、挑选入模特征

# 2.2、对数据切分并统一进行归一化处理

# 3、模型训练与验证

# 3.1、切分数据集将训练集和测试集,并转换为LSTM模型所需的数据格式

# 3.2、将数据转换为LSTM/GRU、CNN所需要的3D格式

# 3.3、构建LSTM/GRU、CNN模型

# 3.4、编译并训练模型

# 3.5、模型预测并将预测结果反归一化为原始值

# 3.6、模型评估

# 3.7、绘制预测值对比真实值

LSTM,epochs = 100

LSTM,epochs = 400

GRU2,epochs = 100

GRU2,epochs = 400

GRU3,epochs = 100

GRU3,epochs = 400

CNN,epochs = 100

CNN,epochs = 400


相关文章
DL之LSTM/GRU/CNN:基于tensorflow框架分别利用LSTM/GRU、CNN算法对上海最高气温实现回归预测案例
DL之LSTM/GRU/CNN:基于tensorflow框架分别利用LSTM/GRU、CNN算法对上海最高气温实现回归预测案例实现代码

基于tensorflow框架分别利用LSTM/GRU、CNN算法对上海最高气温实现回归预测案例

# 1、定义数据集

dateweekmax_temperaturemin_temperatureweatherwind_directionwind_levelair_quality_indexair_quality_level
2021/1/1周五4-1晴~多云西北风2级52
2021/1/2周六71晴~多云东北风2级69
2021/1/3周日106东北风2级66
2021/1/4周一137东风2级44
2021/1/5周二82阴~多云东北风3级49
2021/1/6周三5-4北风3级46
2021/1/7周四-3-6西北风4级67
2021/1/8周五-1-5阴~晴西北风3级50
2021/1/9周六3-1晴~多云西北风3级57
2021/1/10周日5-1阴~多云西北风2级73
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 805 entries, 2021-01-01 to 2023-03-16
Data columns (total 8 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   week               805 non-null    object 
 1   max_temperature    805 non-null    int64  
 2   min_temperature    805 non-null    int64  
 3   weather            805 non-null    object 
 4   wind_direction     805 non-null    object 
 5   wind_level         805 non-null    object 
 6   air_quality_index  667 non-null    float64
 7   air_quality_level  775 non-null    object 
dtypes: float64(1), int64(2), object(5)
memory usage: 56.6+ KB
None
           week  max_temperature  ...  air_quality_index air_quality_level
date                              ...                                     
2021-01-01   周五                4  ...               52.0                 良
2021-01-02   周六                7  ...               69.0                 良
2021-01-03   周日               10  ...               66.0                 良
2021-01-04   周一               13  ...               44.0                 优
2021-01-05   周二                8  ...               49.0                 优
...         ...              ...  ...                ...               ...
2023-03-12   周日               12  ...               68.0                 良
2023-03-13   周一               14  ...               52.0                 良
2023-03-14   周二               20  ...               55.0                 良
2023-03-15   周三               23  ...               52.0                 良
2023-03-16   周四               15  ...               69.0                 良

[805 rows x 8 columns]

# 2、特征工程

# 2.1、挑选入模特征

# 2.2、对数据切分并统一进行归一化处理

(730, 1)
(76, 1)

# 3、模型训练与验证

# 3.1、切分数据集将训练集和测试集,并转换为LSTM模型所需的数据格式

X_train after create_dataset (705, 25) 
            0         1         2   ...        22        23        24
0    0.162791  0.232558  0.302326  ...  0.255814  0.302326  0.418605
1    0.232558  0.302326  0.372093  ...  0.302326  0.418605  0.302326
2    0.302326  0.372093  0.255814  ...  0.418605  0.302326  0.302326
3    0.372093  0.255814  0.186047  ...  0.302326  0.302326  0.302326
4    0.255814  0.186047  0.000000  ...  0.302326  0.302326  0.255814
..        ...       ...       ...  ...       ...       ...       ...
700  0.255814  0.302326  0.302326  ...  0.186047  0.209302  0.232558
701  0.302326  0.302326  0.302326  ...  0.209302  0.232558  0.279070
702  0.302326  0.302326  0.348837  ...  0.232558  0.279070  0.232558
703  0.302326  0.348837  0.372093  ...  0.279070  0.232558  0.209302
704  0.348837  0.372093  0.441860  ...  0.232558  0.209302  0.232558

# 3.2、将数据转换为LSTM/GRU、CNN所需要的3D格式

X_train after reshape (705, 25, 1) 
 [[[0.1627907 ]
  [0.23255814]
  [0.30232558]
  ...
  [0.25581395]
  [0.30232558]
  [0.41860465]]

 [[0.23255814]
  [0.30232558]
  [0.37209302]
  ...
  [0.30232558]
  [0.41860465]
  [0.30232558]]

 [[0.30232558]
  [0.37209302]
  [0.25581395]
  ...
  [0.41860465]
  [0.30232558]
  [0.30232558]]

 ...

 [[0.30232558]
  [0.30232558]
  [0.34883721]
  ...
  [0.23255814]
  [0.27906977]
  [0.23255814]]

 [[0.30232558]
  [0.34883721]
  [0.37209302]
  ...
  [0.27906977]
  [0.23255814]
  [0.20930233]]

 [[0.34883721]
  [0.37209302]
  [0.44186047]
  ...
  [0.23255814]
  [0.20930233]
  [0.23255814]]

# 3.3、构建LSTM/GRU、CNN模型

# 3.4、编译并训练模型

Epoch 1/100
23/23 [==============================] - 3s 9ms/step - loss: 0.0749
Epoch 2/100
23/23 [==============================] - 0s 9ms/step - loss: 0.0135
Epoch 3/100
23/23 [==============================] - 0s 9ms/step - loss: 0.0100
Epoch 4/100
23/23 [==============================] - 0s 9ms/step - loss: 0.0101
Epoch 5/100
23/23 [==============================] - 0s 9ms/step - loss: 0.0097
Epoch 6/100
23/23 [==============================] - 0s 11ms/step - loss: 0.0091
Epoch 7/100
23/23 [==============================] - 0s 10ms/step - loss: 0.0094
Epoch 8/100
23/23 [==============================] - 0s 11ms/step - loss: 0.0097
Epoch 9/100
23/23 [==============================] - 0s 11ms/step - loss: 0.0089
Epoch 10/100
……

Epoch 97/100
23/23 [==============================] - 0s 13ms/step - loss: 0.0059
Epoch 98/100
23/23 [==============================] - 0s 14ms/step - loss: 0.0055
Epoch 99/100
23/23 [==============================] - 0s 13ms/step - loss: 0.0053
Epoch 100/100
23/23 [==============================] - 0s 13ms/step - loss: 0.0053
2/2 [==============================] - 1s 4ms/step
LSTM_val_RMSE: 7.681726490151304
LSTM_val_MSE: 14.169289610796568
LSTM_val_R2: 0.5862969525651983

# 3.5、模型预测并将预测结果反归一化为原始值

# 3.6、模型评估

'''
40 0.51478
25 0.586529
20 0.579569
12   0.5689
6   0.5397
'''

LSTM_val_RMSE: 7.666831051805234
LSTM_val_MSE: 14.324265340141883
LSTM_val_R2: 0.5817721010539598


LSTM_val_RMSE: 7.778038916207498
LSTM_val_MSE: 15.424474218238425
LSTM_val_R2: 0.5496491239544908

# 3.7、绘制预测值对比真实值

LSTM,epochs = 100

LSTM_val_RMSE: 7.7114049938862195
LSTM_val_MSE: 14.225878442019523
LSTM_val_R2: 0.5846447192796375

LSTM,epochs = 400

LSTM_val_RMSE: 7.926438561188859
LSTM_val_MSE: 18.42118750026751
LSTM_val_R2: 0.4621536001055656

GRU2,epochs = 100

GRU2,epochs = 400

GRU_val_RMSE: 7.801296944756388
GRU_val_MSE: 15.746488121878885
GRU_val_R2: 0.5402472317699365

GRU3,epochs = 100

GRU3_val_RMSE: 7.748423445714951
GRU3_val_MSE: 15.642613371982792
GRU3_val_R2: 0.5432800796941399

GRU3,epochs = 400

GRU3_val_RMSE: 7.767935199334584
GRU3_val_MSE: 16.609856586892658
GRU3_val_R2: 0.5150393226336065

CNN,epochs = 100

CNN_val_RMSE: 8.157615491942318
CNN_val_MSE: 26.20883236889009
CNN_val_R2: 0.23477646949527275

CNN,epochs = 400

CNN_val_RMSE: 8.045454928215973
CNN_val_MSE: 36.41909143818048
CNN_val_R2: -0.06333412094997337

以上是关于数值预测案例 LSTM 时间序列气温数据预测,附TensorFlow完整代码的主要内容,如果未能解决你的问题,请参考以下文章

运用自回归滑动平均模型灰色预测模型BP神经网络三种模型分别预测全球平均气温,并进行预测精度对比(附代码数据)

教你搭建多变量时间序列预测模型LSTM(附代码数据集)

基于pytorch搭建多特征LSTM时间序列预测代码详细解读(附完整代码)

LSTM多步时间序列预测+区间预测(附代码实现)

LSTM 对数值数据给出相同的预测

Tensorflow LSTM 模型预测相同的常数值