使用高寒山区输电线路覆冰厚度数据的单一时间序列的LSTM网络

名称:使用高寒山区输电线路覆冰厚度数据的单一时间序列的LSTM网络

具体步骤一览:

1、 时间序列原始数据预处理
2、 时间序列数据集制作
3、 lstm网络训练
4、 lstm网络测试
5、 模型处理结果可视化处理

1、时间序列原始数据预处理

具体步骤:

1、 pandas数据清洗
2、 原始的一维度时间序列数据的平滑处理

pandas数据清洗

因为覆冰厚度文件保存成.csv文件,主要使用pandas读取。

而pandas是一种很好的开源数据处理工具。我对pandas的使用还非常短浅。我认为需要特殊学习一下pandas。

在本次实验中没有用到太多pandas数据清晰的内容,就此略去。

时间序列数据的平滑处理

平滑:包括移动平均平滑、三次指数平滑等方法。其目的就是让变动剧烈的时间数据减少噪声,减少毛刺。

移动平均的代码:

def plotMovingAverage(series, window, plot_intervals=False, scale=1.96, plot_anomalies=False):
    rolling_mean = series.rolling(window = window).mean()
    plt.figure(figsize=(13,5))
    plt.title("Moving average\n window size = {}".format(window))
    plt.plot(rolling_mean, "g", label="Rolling mean trend")
    if plot_intervals:
        mae = mean_absolute_error(series[window:], rolling_mean[window:])
        deviation = np.std(series[window:] - rolling_mean[window:])
        lower_bond = rolling_mean - (mae + scale * deviation)
        upper_bond = rolling_mean + (mae + scale * deviation)
        plt.plot(upper_bond, "r--", label="Upper Bond / Lower Bond")
        plt.plot(lower_bond, "r--")
        # Having the intervals, find abnormal values
        if plot_anomalies:
            anomalies = pd.DataFrame(index=series.index)
            anomalies['series<lower_bond'] = series[series<lower_bond]
            anomalies['series>upper_bond'] = series[series>upper_bond]
            plt.plot(anomalies, "ro", markersize=10)
    plt.plot(series[window:], label="Actual values")
    plt.legend(loc="upper left")
    plt.grid(True)
    return rolling_mean

的确,移动平均的代码我还没有搞懂,这一部分只是我之前找到的博客。

2、 时间序列数据集制作

时间序列数据集在pytorch的框架下,最好是使用Dataset、DataLoader制作。然后就可以循环使用。

时间序列数据集,说白就是(seq,label)的形式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-csiKSIgl-1643079110707)(en-resource://database/585:0)]
以上就是seq,整整30个数据,然后label就是一个数据。
lstm的目的就是用这30个数据来预测最后的一个数据。
在这里,30就是时间窗window。
代码:

# 加载数据的同时实现数据归一化
def load_data(file_name):
    global MAX, MIN
    df = pd.read_csv(file_name)
    columns = df.columns
    data = df[columns[-1]]
    MAX = np.max(data)
    MIN = np.min(data)
    data = (data - MIN) / (MAX - MIN)
    return data

# 数据类
class MyDataset(Dataset):    
def __init__(self, data):        
	self.data = data    
def __getitem__(self, item):       
	return self.data[item]    
def __len__(self):       
	return len(self.data)

# 真正制作时间序列数据集
def making_seq(file_name, batch_size):
    print("创造时序数据")
    data = load_data(file_name)
    load = data.tolist()
    load = torch.FloatTensor(load).view(-1)
    data = data.values.tolist()
    seq = []
    # 30是时间窗,这边就直接认为是这个了。
    for i in range(len(data) - 30):
        train_seq = []
        train_label = []
        for j in range(i, i + 30):
            train_seq.append(load[j])
        train_label.append(load[i + 30])
        train_seq = torch.FloatTensor(train_seq).view(-1)
        train_label = torch.FloatTensor(train_label).view(-1)
        seq.append((train_seq, train_label))

    Dtr = seq[0:int(len(seq) * 0.7)]
    Dte = seq[int(len(seq) * 0.7):len(seq)]

    train_len = int(len(Dtr) / batch_size) * batch_size
    test_len = int(len(Dte) / batch_size) * batch_size
    Dtr, Dte = Dtr[:train_len], Dte[:test_len]

    train = MyDataset(Dtr)
    test = MyDataset(Dte)
	
	# shuffle=Fasle,这样子数据集就是连续的,便于可视化研究
    Dtr = DataLoader(dataset=train, batch_size=batch_size, shuffle=False, num_workers=0)
    Dte = DataLoader(dataset=test, batch_size=batch_size, shuffle=False, num_workers=0)

    return Dtr, Dte

3、lstm网络训练

一、网络定义

很多人的博客上,lstm网络是自己一步步搭建的。本人因为时间有限,就直接引用了pytorch自带的lstm网络结构。

import torch.nn as nn
import torch


class LSTM(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size):
        super().__init__()
        # input_size:专指输入数据的维度数,这里是1
        self.input_size = input_size
        # hidden_size:专指lstm网络内部的节点数,可以自定义,这里是64
        self.hidden_size = hidden_size
        # num_layers:专指网络层数,这里是1层,也可以是多层,可训练时间更长
        self.num_layers = num_layers
        # output_size:专指输入数据的维度数,这里是1
        self.output_size = output_size
        self.batch_size = batch_size
        # num_directions:专指网络是否是双向的,本次是单向的,为1.
        self.num_directions = 1
        self.lstm = nn.LSTM(self.input_size, self.hidden_size, self.num_layers, batch_first=True)
        self.linear = nn.Linear(self.hidden_size, self.output_size)

    def forward(self, input_seq):
        h_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size)
        c_0 = torch.randn(self.num_directions * self.num_layers, self.batch_size, self.hidden_size)
        seq_len = input_seq.shape[1]
        # input(batch_size, seq_len, input_size)
        # input(1, 30, 1)
        input_seq = input_seq.view(self.batch_size, seq_len, 1)
        output, _ = self.lstm(input_seq, (h_0, c_0))
        # 以下这一部分我不太理解
        ouput = output.contiguous().view(self.batch_size * seq_len, self.hidden_size)
        pred = self.linear(output)
        pred = pred.view(self.batch_size, seq_len, -1)
        pred = pred[:, -1, :]
        return pred

二、模型训练:

# name;csv文件路径
# batch_size:自定义的批处理的大小,这里是1,方便后续画图
def LSTM_train(name, batch_size):
    Dtr, Dte = making_seq(file_name=name, batch_size=batch_size)
    input_size, hidden_size, num_layers, output_size = 1, 64, 1, 1
    model = LSTM(input_size, hidden_size, num_layers, output_size, batch_size=batch_size)
    loss_fn = nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
	
	# 迭代循环15次
    epoches = 15
    for i in range(epoches):
    	# cnt:计数器
        cnt = 0
        print("当前", i)
        for (seq, label) in tqdm(Dtr):
            cnt += 1
            y_pred = model(seq)
            loss = loss_fn(y_pred, label)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            if cnt % 100 == 0:
                print('epoch', i, ':', cnt - 100, '~', cnt, loss.item())
    return model

4、 模型测试:

一、一种mape函数:

说实话,我没有仔细研究过这个函数,具体原理我也不是很清楚。

def mape(actual, pred):
    actual, pred = np.array(actual), np.array(pred)
    return np.mean(np.abs((actual - pred) / actual)) * 100

二、测试函数:

import torch.nn as nn
import torch
from tqdm import tqdm
from scipy.interpolate import make_interp_spline
import numpy as np
from itertools import chain
import matplotlib.pyplot as plt


def test(name, b, lstm):
    global MAX, MIN
    Dtr, Dte = making_seq(file_name=name, batch_size=b)
    pred = []
    y = []
    print("loading model....")
    model = torch.load(lstm)
    model.eval()
    print("predicting...")
    for (seq, target) in tqdm(Dte):
        target = list(chain.from_iterable(target.data.tolist()))
        y.extend(target)
        seq_len = seq.shape[1]
        seq = seq.view(model.batch_size, seq_len, 1)
        with torch.no_grad():
            y_pred = model(seq)
            y_pred = list(chain.from_iterable(y_pred.data.tolist()))
            pred.extend(y_pred)

    y, pred = np.array([y]), np.array([pred])
    y = (MAX - MIN) * y + MIN
    pred = (MAX - MIN) * pred + MIN
    print('accuracy:', mape(y, pred))
    # plot
    x = [i for i in range(1, 151)]
    x_smooth = np.linspace(np.min(x), np.max(x), 600)
    y_smooth = make_interp_spline(x, y.T[0:150])(x_smooth)
    plt.plot(x_smooth, y_smooth, c='green', marker='*', ms=1, alpha=0.75, label='true')

    y_smooth = make_interp_spline(x, pred.T[0:150])(x_smooth)
    plt.plot(x_smooth, y_smooth, c='red', marker='o', ms=1, alpha=0.75, label='pred')
    plt.grid(axis='y')
    plt.legend()
    plt.show()

5、最终图像可视化

在这里插入图片描述
这是在整体时间序列数据上的可视化图像,可见前面的训练集数据拟合的很好,可是最后面的大下坡之后的数据就预测的不太准确。而且出现了明显的时间滞后性,这个我就不太明白该如何处理。

本次学习成果记录完成,我想要再次写下自己目前拓展的领域,记录下自己的不足之处。

学习是一个不断进步的过程,这次我学会了真正训练lstm网络,粗略涉及了时间序列数据挖掘领域。但是这有一次深深刺痛我身上的弱点。
1、 查找博客和相关资料时候目标不明确,信息来源不可靠——以后要尽可能使用一些指标,或者说囤积可靠的网址。
2、 python语言的使用不熟练,针对python面向对象的书写还几乎为0
3、 pytorch运用不熟练,我还是不熟悉pytorch的运行机制、pytorch其中神奇的小工具,每一次新的尝试都会耗费大量精力。坦诚的说,每一次课程设计,技术储备时间比真正的课设设计时间要多出10倍不止,这极大限制我学习的进度。
4、 数据挖掘不熟悉,针对一个固定的数据集,训练模型前无法有效分析数据以选择相关的模型,模型训练出来也无法判断结果的好坏。
5、 计算机基础知识匮乏,电脑出了故障还需要自己去找修电脑的,真的是笑死人了。

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值