Py学习  »  机器学习算法

LSTM | 使用深度学习来预测气温

气象学家 • 1 年前 • 355 次点击  

本文实现用LSTM来进行气温的预测(与另外一篇文章一样,但是觉得是属于时空数据处理的系列,就重复发一遍)。


导入包:

import pandas as pd
import torch
import torch.nn as nn
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.model_selection import train_test_split
import numpy as np
import datetime as dt
import matplotlib.pyplot as plt

数据

读取和预处理数据:

df = pd.read_csv(r'data.csv')
df = df.loc[:,['id','date','tave']]
df = df.groupby(['date'])['tave'].mean().reset_index()
df['date'] =  pd.to_datetime(df.date)
df = df.set_index('date', drop=True)
df.head()

数据大概这样子:

可视化一下:

x = [dt.datetime.date(d) for d in df.index]
fig = plt.figure(figsize=(10,5))
plt.title('Temperature Changing with Time')
plt.ylabel('Temperature/K')
plt.grid(True)
plt.plot(x[:],
         df.tave[:],
         "b-",label="Temperature")
plt.legend()
温度变化

对数据进行处理,分割为train和test:

def train_test(df, test_periods):
    train = df[:-test_periods].tave
    test = df[-test_periods:].tave
    return train, test
test_periods = 30
train, test = train_test(df, test_periods)
train = train.to_frame()
test = test.to_frame()

然后对数据进行归一化:

scaler = MinMaxScaler()
scaler.fit(train)
train_scaled = scaler.transform(train)
train_scaled = torch.FloatTensor(train_scaled)
print(f'Original dimensions : {train_scaled.shape}')
train_scaled = train_scaled.view(-1)
print(f'Correct dimensions : {train_scaled.shape}')

Original dimensions : torch.Size([14212, 1])
Correct dimensions : torch.Size([14212])

在深度学习模型中,我们需要的配对的X和Y,用下面的代码生成匹配的X和Y:

def get_x_y_pairs(train_scaled, train_periods, prediction_periods):
    """
    train_scaled - training sequence
    train_periods - How many data points to use as inputs
    prediction_periods - How many periods to ouput as predictions
    "
""
    x_train = [train_scaled[i:i+train_periods] for i in range(len(train_scaled)-train_periods-prediction_periods)]
    y_train = [train_scaled[i+train_periods:i+train_periods+prediction_periods] for i in  range(len(train_scaled)-train_periods-prediction_periods)]
    
    #-- use the stack function to convert the list of 1D tensors
    # into a 2D tensor where each element of the list is now a row
    x_train = torch.stack(x_train)
    y_train = torch.stack(y_train)
    
    return x_train, y_train

train_periods = 60 #-- number of quarters for input
prediction_periods = test_periods # 30
x_train, y_train = get_x_y_pairs(train_scaled, train_periods, prediction_periods)
print(x_train.shape)
print(y_train.shape)
torch.Size([14122, 60])
torch.Size([14122, 30])

模型

LSTM的原理网上有很多,可以随便找个看看,用下面的代码就可以定义一个LSTM模型:

class LSTM(nn.Module):
    """
    input_size - will be 1 in this example since we have only 1 predictor (a sequence of previous values)
    hidden_size - Can be chosen to dictate how much hidden "
long term memory" the network will have
    output_size - This will be equal to the prediciton_periods input to get_x_y_pairs
    "
""
    def __init__(self, input_size, hidden_size, output_size,device='cuda'):
        super(LSTM, self).__init__()
        self.hidden_size = hidden_size
        
        self.lstm = nn.LSTM(input_size, hidden_size)
        
        self.linear = nn.Linear(hidden_size, output_size)
        
    def forward(self, x, hidden=None):
        if hidden==None:
            self.hidden = (torch.zeros(1,1,self.hidden_size).to('cuda'),
                           torch.zeros(1,1,self.hidden_size).to('cuda'))
            
        else:
            self.hidden = hidden
        # self.hidden = self.hidden.to(device)
            
        """
        inputs need to be in the right shape as defined in documentation
        - https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html
        
        lstm_out - will contain the hidden states from all times in the sequence
        self.hidden - will contain the current hidden state and cell state
        "
""
        lstm_out, self.hidden = self.lstm(x.view(len(x),1,-1), 
                                          self.hidden)
        
        predictions = self.linear(lstm_out.view(len(x), -1))
        
        return predictions[-1], self.hidden

损失函数和优化器

model = LSTM(input_size=1, hidden_size=50, output_size=test_periods,device='cuda')
model = model.to('cuda')
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

迭代训练

epochs = 10
model.train()
for epoch in range(epochs+1):
    for x,y in zip(x_train, y_train):
        x = x.to('cuda')
        y = y.to('cuda')
        # print(x.shape)
        # print(y.shape)
        y_hat, _ = model(x, None)
        optimizer.zero_grad()
        loss = criterion(y_hat, y)
        loss.backward()
        optimizer.step()
        
    # # if epoch%100==0:
    print(f'epoch: {epoch:4} loss:{loss.item():10.8f}')
epoch:    0 loss:0.02134472
epoch:    1 loss:0.01335849
epoch:    2 loss:0.01380302
epoch:    3 loss:0.01341427
epoch:    4 loss:0.01298358
epoch:    5 loss:0.01258101
epoch:    6 loss:0.01235029
epoch:    7 loss:0.01221257
epoch:    8 loss:0.01209989
epoch:    9 loss:0.01199529
epoch:   10 loss:0.01189370

测试结果

model.eval()
with torch.no_grad():
    val_x = train_scaled[-train_periods:].to('cuda')
    predictions, _ = model(val_x, None)
    predictions = predictions.cpu().numpy()
#-- Apply inverse transform to undo scaling
predictions = scaler.inverse_transform(np.array(predictions.reshape(-1,1)))

可视化看下:




    
x = [dt.datetime.date(d) for d in df.index]
fig = plt.figure(figsize=(10,5))
plt.title('Temperature Changing with Time')
plt.ylabel('Temperature/K')
plt.grid(True)
plt.plot(x[:-len(predictions)],
         df.tave[:-len(predictions)],
         "b-")
plt.plot(x[-len(predictions):],
         df.tave[-len(predictions):],
         "b--",
         label='True Values')
plt.plot(x[-len(predictions):],
         predictions,
         "r-",
         label='Predicted Values')
plt.legend()

好像看不太清楚,因为一共就预测了30天的数据,整个时间序列是几十年的。我们只看下预测的这30天的真值和预测值的对比:

x = [dt.datetime.date(d) for d in df.index]
fig = plt.figure(figsize=(10,5))
plt.title('Temperature Changing with Time')
plt.ylabel('Temperature/K')
plt.grid(True)
plt.plot(x[-len(predictions):],
         df.tave[-len(predictions):],
         "b--",
         label='True Values')
plt.plot(x[-len(predictions):],
         predictions,
         "r-",
         label='Predicted Values')
plt.legend()

好像结果很垃圾。。但是我的模型只训练了10个epoch,应该远远不够,大家可以用自己的数据来试一下。

参考

【1】https://www.statology.org/pandas-groupby-sum/
【2】https://medium.com/towards-data-science/lstm-for-time-series-prediction-de8aeb26f2ca
【3】https://medium.com/gitconnected/forecasting-walmart-quarterly-revenue-pytorch-lstm-example-b4e4b20862a7

声明:欢迎转载、转发本号原创内容,可留言区留言或者后台联系小编(微信:gavin7675)进行授权。气象学家公众号转载信息旨在传播交流,其内容由作者负责,不代表本号观点。文中部分图片来源于网络,如涉及作品内容、版权和其他问题,请后台联系小编处理。





往期推荐

 ERA5-Land陆面高分辨率再分析数据(~16TB)

★ ERA5常用变量再分析数据(~11TB)

 TRMM 3B42降水数据(Daily/3h)

 科研数据免费共享: GPM卫星降水数据

 气象圈子有人就有江湖,不要德不配位!

 请某气象公众号不要 “以小人之心,度君子之腹”!

 EC数据商店推出Python在线处理工具箱

★ EC打造实用气象Python工具Metview

★ 机器学习简介及在短临天气预警中的应用

★ AMS推荐|气象学家-海洋学家的Python教程

★ Nature-地球系统科学领域的深度学习及理解

★ 采用神经网络与深度学习来预报降水、温度


   欢迎加入气象学家交流群   

请备注:姓名/昵称-单位/学校-研究方向

未备注的不通过申请



❤️ 「气象学家」 点赞

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/138810
 
355 次点击