社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  机器学习算法

代码共享 | 利用深度学习预测气温

happy科研 • 1 年前 • 338 次点击  

本文实现用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



往 期 推 荐
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/146265
 
338 次点击