使用了LSTM的数据预测

发布于:2024-08-26 ⋅ 阅读:(132) ⋅ 点赞:(0)

记录一下,这个是在national university of singapore,黄教授给我们布置的任务,做了一个北京的已知十年的打印量,预测100天的打印机大作业,我们使用了lstm模型,就是两层神经网络,同时dropout的加入为了防止过拟合问题,验证集是最后的100个,后续优化打算往里面使用聚类,加入neuralprophet,效果应该会更好,也可以加入GANs

import numpy as np  # 导入NumPy库,用于数学运算
import pandas as pd  # 导入Pandas库,用于数据分析
import datetime  # 导入datetime库,用于处理日期和时间
from sklearn.preprocessing import MinMaxScaler  # 从sklearn库导入MinMaxScaler,用于数据标准化
from tensorflow.keras.models import Sequential  # 从Keras库导入Sequential模型,用于构建神经网络
from tensorflow.keras.layers import LSTM, Dense, Dropout  # 从Keras库导入LSTM, Dense, Dropout层
import matplotlib.pyplot as plt  # 导入matplotlib.pyplot,用于数据可视化

# 定义一个转换数据的函数
def transform(path):
    df = pd.read_csv(open(path, 'rb'), low_memory=False)  # 读取CSV文件到DataFrame
    printerIdx = np.array(df['printerIndex'])  # 从DataFrame中提取打印机索引
    usage = np.array(df['usage'])  # 提取使用数据
    date = np.array(df['date'])  # 提取日期数据

    numofkinds = len(np.unique(printerIdx))  # 计算不同打印机种类的数量
    numofday = len(np.unique(date))  # 计算不同日期的数量

    date = np.unique(date)  # 获取唯一的日期数组
    usage = np.reshape(usage, [numofkinds, numofday])  # 重塑使用数据数组以匹配打印机种类和日期

    df_output = pd.DataFrame(usage)  # 创建新的DataFrame来存储使用数据
    df_output.columns = date  # 将日期设置为DataFrame的列

    return df_output  # 返回处理后的数据集

# 定义数据加载函数
def DataLoading(path):
    Dataset = transform(path)  # 调用transform函数处理数据
    TOTALDAYNUM = Dataset.shape[1]  # 获取数据集中的日期总数
    TOTALDEVICENUM = Dataset.shape[0]  # 获取数据集中的设备总数

    # 遍历日期列,将字符串转换为datetime对象
    for colIdx in range(TOTALDAYNUM):
        tmpDate = datetime.datetime.strptime(Dataset.columns[colIdx], '%Y-%m-%d %H:%M:%S.%f')
        Dataset.rename(columns={Dataset.columns[colIdx]: tmpDate}, inplace=True)

    Dataset = Dataset.transpose()  # 转置数据集
    Dataset.index.name = 'Datetime'  # 将索引名称设置为Datetime
    Dataset.reset_index(inplace=True)  # 重置索引

    # 遍历设备列,重命名列以匹配打印机索引
    for colIdx in range(TOTALDEVICENUM):
        tmpColName = 'PrinterIdx' + str(Dataset.columns[colIdx + 1])
        Dataset.rename(columns={Dataset.columns[colIdx + 1]: tmpColName}, inplace=True)

    date = Dataset.iloc[:, 0].values  # 获取日期列
    return Dataset, date  # 返回处理后的数据集和日期

# 定义LSTM预测、可视化和保存结果的函数
def predict_and_save(path, save_path):
    # 加载数据
    Dataset, date = DataLoading(path)

    # 标准化数据
    scaler = MinMaxScaler(feature_range=(0, 1))  # 创建MinMaxScaler实例
    scaled_data = scaler.fit_transform(Dataset.iloc[:, 1:].values)  # 对数据进行标准化

    # 定义创建时间序列数据集的函数
    def create_dataset(data, look_back=100):
        X, Y = [], []  # 初始化X和Y列表
        # 遍历数据,创建时间序列数据集
        for i in range(len(data) - look_back):
            X.append(data[i:i + look_back])
            Y.append(data[i + look_back])
        return np.array(X), np.array(Y)

    look_back = 100  # 设置时间步长
    X, Y = create_dataset(scaled_data, look_back)  # 创建数据集

    # 划分训练集和测试集
    trainX, testX = X[:-look_back], X[-look_back:]  # 分割X数据集
    trainY, testY = Y[:-look_back], Y[-look_back:]  # 分割Y数据集

    # 调整形状以适配LSTM网络
    trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], trainX.shape[2]))
    testX = np.reshape(testX, (testX.shape[0], testX.shape[1], testX.shape[2]))

    # 构建LSTM模型
    model = Sequential()  # 创建Sequential模型
    model.add(LSTM(50, return_sequences=True, input_shape=(trainX.shape[1], trainX.shape[2])))
    model.add(Dropout(0.2))  # 添加Dropout层防止过拟合
    model.add(LSTM(50))
    model.add(Dropout(0.2))  # 再次添加Dropout层防止过拟合
    model.add(Dense(Dataset.shape[1] - 1))  # 添加Dense层进行预测

    model.compile(optimizer='adam', loss='mean_squared_error')  # 编译模型

    # 训练模型
    model.fit(trainX, trainY, epochs=50, batch_size=32, validation_data=(testX, testY))

    # 预测未来100天的打印量
    futureX = testX[-1].reshape(1, look_back, Dataset.shape[1] - 1)  # 准备输入数据
    predictions = []  # 初始化预测结果列表
    for _ in range(100):  # 进行100次预测
        pred = model.predict(futureX)  # 预测
        predictions.append(pred[0])  # 添加预测结果
        futureX = np.roll(futureX, -1, axis=1)  # 滚动输入数据
        futureX[0, -1] = pred  # 更新最后一个时间步的数据

    # 反标准化预测结果
    predictions = scaler.inverse_transform(predictions)

    # 后处理:确保所有预测值为非负数
    predictions = np.clip(predictions, 0, None)

    # 保存结果到CSV
    prediction_df = pd.DataFrame(predictions, columns=Dataset.columns[1:])  # 创建DataFrame
    future_dates = pd.date_range(start=date[-1], periods=101, freq='D')[1:]  # 生成未来日期
    prediction_df['Date'] = future_dates  # 添加日期列
    prediction_df.set_index('Date', inplace=True)  # 将日期设置为索引

    # 保存到指定路径
    prediction_df.to_csv(save_path)  # 保存CSV文件
    print(f"Predictions saved to {save_path}")  # 打印保存信息

    # 可视化
    plt.figure(figsize=(12, 6))  # 创建图形
    for column in prediction_df.columns:  # 遍历列
        plt.plot(prediction_df.index, prediction_df[column], label=column)  # 绘制折线图

    plt.title('Predicted Printer Usage for the Next 100 Days')  # 设置标题
    plt.xlabel('Date')  # 设置X轴标签
    plt.ylabel('Predicted Usage')  # 设置Y轴标签
    plt.legend(loc='upper right')  # 设置图例位置
    plt.show()  # 显示图形

# 使用示例
data_path = 'D:\\桌面\\singapore\\Model_Beijing_Assignment.csv'  # 数据文件路径
save_path = 'D:\\桌面\\singapore\\prediction.CSV'  # 预测结果保存路径
predict_and_save(data_path, save_path)  # 调用函数进行预测并保存结果

最后还加了可视化,挺直观的
数据集也已经绑定