「实战案例:使用 LSTM 进行单变量时间序列预测(附Python完整代码)

LSTM介绍

        LSTM(长短时记忆网络)是一种特殊类型的循环神经网络(RNN),用于处理和预测时间序列数据。相比于传统的RNN,LSTM具有更好的处理长期依赖性和记忆能力。关键思想是引入了一个称为"记忆单元"的组件。记忆单元能够接收输入、输出和保留信息,以便在整个序列中传递和保存重要的信息。这种机制使得LSTM能够更好地处理长序列,避免梯度消失问题,并且具有较长的记忆。其结构包括三个主要的门控单元:输入门、遗忘门和输出门。输入门决定了多少输入信息应该被记忆,遗忘门决定了多少旧的记忆应该被遗忘,输出门决定了多少记忆应该输出给下一个时间步。训练过程通常使用反向传播算法和梯度下降法来更新网络参数。在训练过程中,LSTM可以通过学习时间序列数据中的模式和规律来预测未来的值。

单变量时间预测

数据是github上下载ETTh1.csv转换的,我用的是时间和OT列

预测结果图

数据集

        是从github上下载的油温数据ETTh1.csv,只用了里面的时间列和OT列,具体地址不记得了,需要数据集的和我说一下。

完整代码

import csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import r2_score
import tensorflow as tf
from tensorflow.python.keras import Sequential, layers, utils


def predict_next(model, sample, epoch=20):
    temp1 = list(sample[:, 0])
    for i in range(epoch):
        sample = sample.reshape(1, x_Seq_len, 1)
        pred = model.predict(sample)
        value = pred.tolist()[0][0]
        temp1.append(value)
        sample = np.array(temp1[i + 1 : i + x_Seq_len + 1])
    return temp1


def create_new_dataset(dataset, seq_len=12):
    """基于原始数据集构造新的序列特征数据集
    Params:
        dataset : 原始数据集
        seq_len : 序列长度(时间跨度)
    Returns:
        X, y
    """
    X = []  # 初始特征数据集为空列表
    y = []  # 初始标签数据集为空列表,y标签为样本的下一个点,即预测点

    start = 0  # 初始位置
    end = dataset.shape[0] - seq_len  # 截止位置,dataset.shape[0]就是有多少条

    for i in range(start, end):  # for循环构造特征数据集
        sample = dataset[i : i + seq_len]  # 基于时间跨度seq_len创建样本
        label = dataset[i + seq_len]  # 创建sample对应的标签
        X.append(sample)  # 保存sample
        y.append(label)  # 保存label
    # 返回特征数据集和标签集
    return np.array(X), np.array(y)


def split_dataset(X, y, train_ratio=0.8):
    """基于X和y,切分为train和test
    Params:
        X : 特征数据集
        y : 标签数据集
        train_ratio : 训练集占X的比例

    Returns:
        X_train, X_test, y_train, y_test
    """
    X_len = len(X)  # 特征数据集X的样本数量
    train_data_len = int(X_len * train_ratio)  # 训练集的样本数量

    X_train = X[:train_data_len]  # 训练集
    y_train = y[:train_data_len]  # 训练标签集

    X_test = X[train_data_len:]  # 测试集
    y_test = y[train_data_len:]  # 测试集标签集

    # 返回值
    return X_train, X_test, y_train, y_test


# 功能函数:基于新的X_train, X_test, y_train, y_test创建批数据(batch dataset)


def create_batch_data(X, y, batch_size=32, data_type=1):
    """基于训练集和测试集,创建批数据
    Params:
        X : 特征数据集
        y : 标签数据集
        batch_size : batch的大小,即一个数据块里面有几个样本
        data_type : 数据集类型(测试集表示1,训练集表示2)

    Returns:
        train_batch_data 或 test_batch_data
    """
    if data_type == 1:  # 测试集
        dataset = tf.data.Dataset.from_tensor_slices(
            (tf.constant(X), tf.constant(y))
        )  # 封装X和y,成为tensor类型
        test_batch_data = dataset.batch(batch_size)  # 构造批数据
        # 返回
        return test_batch_data
    else:  # 训练集
        dataset = tf.data.Dataset.from_tensor_slices(
            (tf.constant(X), tf.constant(y))
        )  # 封装X和y,成为tensor类型
        train_batch_data = dataset.cache().shuffle(1000).batch(batch_size)  # 构造批数据
        # 返回
        return train_batch_data


if __name__ == "__main__":
    plt.rcParams["font.sans-serif"] = ["SimHei"]  # 显示中文标签
    plt.rcParams["axes.unicode_minus"] = False  # 解决负数问题
    x_Seq_len = 32  # 16
    # dataset = pd.read_csv("transform\data\data_pre_all_new.csv")
    dataset = pd.read_csv("transform\ETTh1.csv")
    dataset = dataset.iloc[:, [0, 7]]
    dataset.columns = ["date", "OT"]
    dataset["date"] = pd.to_datetime(
        dataset["date"],
        format="%Y-%m-%d %H:%M:%S",
        # dataset["date"],
        # format="%Y-%m-%d",
    )
    aa = dataset.date
    dataset.index = dataset.date  # 将其索引变为时间
    dataset.drop(columns="date", axis=1, inplace=True)
    plt.figure()
    plt.plot(dataset)
    plt.show()
    """
    数据清洗
    """
    # 缺失值处理
    # 查看是否有缺失值
    print(dataset.info())  # 无缺失值
    # print(dataset[dataset.isnull()==False])#无
    # dataset['总有功功率(kw)']=dataset['总有功功率(kw)'].fillna(0) 对缺失值填值处理
    # dataset1=dataset[dataset['总有功功率(kw)'].notnull()] 剔除存在缺失值的数据,自己选择一直缺失值处理的方法

    # 异常值处理
    # dataset = dataset.reset_index(drop=True)
    # dataset = pd.concat([aa, dataset], axis=1)
    # print(dataset)  # (17420, 2) 索引
    # exit()
    """
    箱型图查看
    """
    f, ax = plt.subplots()
    sns.boxplot(y="OT", data=dataset, ax=ax)
    plt.show()
    s = dataset.describe()

    # 基本统计量,存在异常值的将其筛选出来进行处理,可以用中位数填值或者众数填值,方法任选,这里没有异常值就没有处理
    q1 = s.loc["25%"]
    q3 = s.loc["75%"]
    iqr = q3 - q1  # 分位差
    mi = q1 - 1.5 * iqr  # 下限,低于这个为异常值
    ma = q3 + 1.5 * iqr  # 上限,高于这个为异常值
    # print(dataset)
    # print(dataset.shape) #(17420, 1)
    # 寻找异常点,获得异常点索引值,删除索引值所在行数据
    dataset = dataset.drop(
        index=(
            dataset[
                ((dataset.OT) > float(ma.values)) | ((dataset.OT) < float(mi.values))
            ].index
        )
    )
    # print(dataset.shape)  # (16949, 1)
    # print(dataset)
    # 筛选异常值

    # 归一化处理,均值为0,方差为1
    scaler = MinMaxScaler()
    dataset["OT"] = scaler.fit_transform(dataset["OT"].values.reshape(-1, 1))
    # 将归一化的数据保持
    with open("data.csv", "w", encoding="utf-8", newline="") as f:
        w = csv.writer(f)
        w.writerow(dataset["OT"])
    # 归一化后的绘图
    dataset["OT"].plot()
    plt.show()
    """
    特征提取(特征工程)
    """
    dataset_new = dataset
    # X为特征数据集,y为标签数据集
    X, y = create_new_dataset(dataset_new.values, seq_len=x_Seq_len)
    # X_train为数据训练集,X_test为数据测试集,y_train为标签训练集,y_test为标签测试集合
    X_train, X_test, y_train, y_test = split_dataset(X, y)
    # 基于新的X_train, X_test, y_train, y_test创建批数据(batch dataset)
    # 测试批数据
    test_batch_dataset = create_batch_data(X_test, y_test, batch_size=24, data_type=1)
    # 训练批数据
    train_batch_dataset = create_batch_data(
        X_train, y_train, batch_size=24, data_type=2
    )
    """
     构建模型
    """
    model = Sequential(
        [layers.LSTM(8, input_shape=(x_Seq_len, 1)), layers.Dense(1)]
    )  # 8
    # 定义 checkpoint,保存权重文件
    file_path = "best_checkpoint.hdf5"  # 将数据加载到内存
    checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
        filepath=file_path,
        monitor="loss",
        mode="min",
        save_best_only=True,
        save_weights_only=True,
    )
    """
     编译运行预测
    """
    # 模型编译
    model.compile(optimizer="adam", loss="mae")
    # 模型训练(次数200)
    history = model.fit(
        train_batch_dataset,
        epochs=100,  # 100
        validation_data=test_batch_dataset,
        callbacks=[checkpoint_callback],
    )
    # 显示 train loss 和 val loss
    plt.figure()
    plt.plot(history.history["loss"], label="train loss")
    plt.plot(history.history["val_loss"], label="val loss")
    plt.title("LOSS")
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend(loc="best")
    plt.show()
    # 模型验证
    test_pred = model.predict(X_test, verbose=1)
    plt.figure()
    d1 = plt.plot(y_test, label="True")
    d2 = plt.plot(test_pred, label="pred")
    plt.legend([d1, d2], labels=["True", "pred"])
    plt.show()
    # 计算r2
    score = r2_score(y_test, test_pred)
    print("r^2 的值: ", score)
    # 绘制test中前100个点的真值与预测值
    y_true = y_test  # 真实值
    y_pred = test_pred  # 预测值

    fig, axes = plt.subplots(2, 1)
    ax0 = axes[0].plot(y_true, marker="o", color="red", label="true")
    ax1 = axes[1].plot(y_pred, marker="*", color="blue", label="pred")
    plt.show()
    """
    模型测试
    """
    # 选择test中的最后一个样本
    sample = X_test[-1]
    sample = sample.reshape(1, sample.shape[0], 1)
    # 模型预测
    sample_pred = model.predict(sample)  # predict()预测标签值
    ture_data = X_test[-1]  # 真实test的最后20个数据点
    # 预测后48个点
    preds = predict_next(model, ture_data, 48)
    # 绘图
    plt.figure()
    plt.plot(preds, color="yellow", label="Prediction")
    plt.plot(ture_data, color="blue", label="Truth")
    plt.xlabel("Epochs")
    plt.ylabel("Value")
    plt.legend(loc="best")
    plt.show()
relative_error = 0
"""模型精确度计算"""
for i in range(len(y_pred)):
    relative_error += (abs(y_pred[i] - y_true[i]) / y_true[i]) ** 2
acc = 1 - np.sqrt(relative_error / len(y_pred))
print(f"模型的测试准确率为:", acc)

  

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TensorFlow是一个开源的深度学习框架,拥有丰富的API和工具,可以用于各种应用场景,包括股票数据预测。在这个案例中,我们将使用LSTM(长短期记忆)和GRU(门控循环元)这两种常用的循环神经网络模型,对股票数据进行预测。以下是Python完整代码示例: ```python import tensorflow as tf import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler # 读取数据 data = pd.read_csv('stock_data.csv') close_prices = data['close'].values.reshape(-1, 1) # 数据预处理 scaler = MinMaxScaler() scaled_close_prices = scaler.fit_transform(close_prices) # 划分训练集和测试集 train_size = int(len(scaled_close_prices) * 0.8) train_data = scaled_close_prices[:train_size] test_data = scaled_close_prices[train_size:] # 构建训练集和测试集 def create_dataset(data): X, y = [], [] for i in range(len(data) - 60): X.append(data[i:i+60]) y.append(data[i+60]) return np.array(X), np.array(y) X_train, y_train = create_dataset(train_data) X_test, y_test = create_dataset(test_data) # 构建LSTM模型 model_lstm = tf.keras.Sequential([ tf.keras.layers.LSTM(50, return_sequences=True, input_shape=(60, 1)), tf.keras.layers.LSTM(50), tf.keras.layers.Dense(1) ]) model_lstm.compile(optimizer='adam', loss='mean_squared_error') model_lstm.fit(X_train, y_train, epochs=10, batch_size=32) # 构建GRU模型 model_gru = tf.keras.Sequential([ tf.keras.layers.GRU(50, return_sequences=True, input_shape=(60, 1)), tf.keras.layers.GRU(50), tf.keras.layers.Dense(1) ]) model_gru.compile(optimizer='adam', loss='mean_squared_error') model_gru.fit(X_train, y_train, epochs=10, batch_size=32) # 模型预测 predictions_lstm = model_lstm.predict(X_test) predictions_gru = model_gru.predict(X_test) # 反归一化 scaled_predictions_lstm = scaler.inverse_transform(predictions_lstm) scaled_predictions_gru = scaler.inverse_transform(predictions_gru) scaled_y_test = scaler.inverse_transform(y_test) # 评估模型 def evaluate_model(predictions, y): rmse = np.sqrt(np.mean((predictions - y) ** 2)) return rmse rmse_lstm = evaluate_model(scaled_predictions_lstm, scaled_y_test) rmse_gru = evaluate_model(scaled_predictions_gru, scaled_y_test) print('LSTM模型的RMSE:', rmse_lstm) print('GRU模型的RMSE:', rmse_gru) ``` 在这个案例中,我们首先读取了股票数据,并进行了数据预处理,包括数据归一化和训练集和测试集的划分。然后,我们使用LSTM和GRU分别构建了模型,并训练了模型。接下来,我们使用模型对测试集进行预测,并对预测结果进行反归一化。最后,我们评估了模型的性能,使用均方根误差(RMSE)作为评估指标。输出结果中,LSTM模型的RMSE和GRU模型的RMSE可以帮助我们了解模型预测的准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值