使用LSTM深度學習模型進行溫度的時間序列單步和多步預測

2020-12-12 deephub

本文的目的是提供代碼示例,並解釋使用python和TensorFlow建模時間序列數據的思路。

本文展示了如何進行多步預測並在模型中使用多個特徵。

本文的簡單版本是,使用過去48小時的數據和對未來1小時的預測(一步),我獲得了溫度誤差的平均絕對誤差0.48(中值0.34)度。

利用過去168小時的數據並提前24小時進行預測,平均絕對誤差為攝氏溫度1.69度(中值1.27)。

所使用的特徵是過去每小時的溫度數據、每日及每年的循環信號、氣壓及風速。

使用來自https://openweathermap.org/的API獲取數據。這些數據從1990年1月1日到2020.11月30日每小時在維爾紐斯電視塔附近收集一次。維爾紐斯不是一個大城市,電視塔就在城市裡,所以電視塔附近的溫度應該和城市所有地方的溫度非常相似。

這裡和整篇文章的主數據對象被稱為d。它是通過讀取原始數據創建的:

d = pd.read_csv(『data/weather.csv』)# Converting the dt column to datetime object d[『dt』] = [datetime.datetime.utcfromtimestamp(x) for x in d[『dt』]]# Sorting by the date d.sort_values(『dt』, inplace=True)

數據集中共有271008個數據點。

數據似乎是具有明確的周期模式。

上面的圖表顯示,氣溫有一個清晰的晝夜循環——中間溫度在中午左右最高,在午夜左右最低。

這種循環模式在按月份分組的溫度上更為明顯——最熱的月份是6月到8月,最冷的月份是12月到2月。

數據現在的問題是,我們只有date列。如果將其轉換為數值(例如,提取時間戳(以秒為單位))並將其作為建模時的特性添加,那麼循環特性將丟失。因此,我們需要做的第一件事就是設計一些能夠抓住周期性趨勢的特性。

我們想讓機器知道,23點和0點比小時0點和4點更接近。我們知道周期是24小時。我們可以用cos(x)和sin(x)函數。函數中的x是一天中的一個小時。

# Extracting the hour of dayd["hour"] = [x.hour for x in d["dt"]]# Creating the cyclical daily feature d["day_cos"] = [np.cos(x * (2 * np.pi / 24)) for x in d["hour"]]d["day_sin"] = [np.sin(x * (2 * np.pi / 24)) for x in d["hour"]]

得到的dataframe如下:

新創建的特徵捕捉了周期性模式。 可能會出現一個問題,為什麼我們同時使用sin和cos函數?

在上圖中繪製一條水平線並僅分析其中一條曲線,我們將得到例如cos(7.5h)= cos(17.5h)等。 在學習和預測時,這可能會導致一些錯誤,因此為了使每個點都唯一,我們添加了另一個循環函數。 同時使用這兩個功能,可以將所有時間區分開。

為了在一年中的某個時間創建相同的循環邏輯,我們將使用時間戳功能。 python中的時間戳是一個值,用於計算自1970.01.01 0H:0m:0s以來經過了多少秒。 python中的每個date對象都具有timestamp()函數。

# Extracting the timestamp from the datetime object d["timestamp"] = [x.timestamp() for x in d["dt"]]# Seconds in day s = 24 * 60 * 60# Seconds in year year = (365.25) * sd["month_cos"] = [np.cos((x) * (2 * np.pi / year)) for x in d["timestamp"]]d["month_sin"] = [np.sin((x) * (2 * np.pi / year)) for x in d["timestamp"]]

在本節中,我們從datetime列中創建了4個其他功能:daysin,daycos,monthsin和monthcos。

在天氣數據集中,還有兩列:wind_speed和pressure。 風速以米/秒(m / s)為單位,壓力以百帕斯卡(hPa)為單位。

要查看溫度與兩個特徵之間的任何關係,我們可以繪製二維直方圖:

顏色越強烈,兩個分布的某些bin值之間的關係就越大。 例如,當壓力在1010和1020 hPa左右時,溫度往往會更高。

我們還將在建模中使用這兩個功能。

我們使用所有要素工程獲得的數據是:

我們要近似的函數f為:

目標是使用過去的值來預測未來。 數據是時間序列或序列。 對於序列建模,我們將選擇具有LSTM層的遞歸神經網絡的Tensorflow實現。

LSTM網絡的輸入是3D張量:

(樣本,時間步長,功能)

樣本—用於訓練的序列總數。

timesteps-樣本的長度。

功能-使用的功能數量。

建模之前的第一件事是將2D格式的數據轉換為3D數組。 以下功能可以做到這一點:

例如,如果我們假設整個數據是數據的前10行,那麼我們將過去3個小時用作特徵,並希望預測出1步:

def create_X_Y(ts: np.array, lag=1, n_ahead=1, target_index=0) -> tuple:""" A method to create X and Y matrix from a time series array for the training of deep learning models """ # Extracting the number of features that are passed from the array n_features = ts.shape[1] # Creating placeholder lists X, Y = [], [] if len(ts) - lag <= 0: X.append(ts) else: for i in range(len(ts) - lag - n_ahead): Y.append(ts[(i + lag):(i + lag + n_ahead), target_index]) X.append(ts[i:(i + lag)]) X, Y = np.array(X), np.array(Y) # Reshaping the X array to an RNN input shape X = np.reshape(X, (X.shape[0], lag, n_features)) return X, Y

例如,如果我們假設整個數據是數據的前10行,那麼我們將過去3個小時用作特徵,並希望預測出1步:

ts = d[『temp』, 『day_cos』, 『day_sin』, 『month_sin』, 『month_cos』, 『pressure』, 『wind_speed』].head(10).valuesX, Y = create_X_Y(ts, lag=3, n_ahead=1)

如我們所見,X矩陣的形狀是6個樣本,3個時間步長和7個特徵。 換句話說,我們有6個觀測值,每個觀測值都有3行數據和7列。 之所以有6個觀測值,是因為前3個滯後被丟棄並且僅用作X數據,並且我們預測提前1步,因此最後一個觀測值也會丟失。

上圖中顯示了X和Y的第一個值對。

最終模型的超參數列表:

# Number of lags (hours back) to use for modelslag = 48# Steps ahead to forecast n_ahead = 1# Share of obs in testing test_share = 0.1# Epochs for trainingepochs = 20# Batch size batch_size = 512# Learning ratelr = 0.001# Number of neurons in LSTM layern_layer = 10# The features used in the modeling features_final = [『temp』, 『day_cos』, 『day_sin』, 『month_sin』, 『month_cos』, 『pressure』, 『wind_speed』]

模型代碼

class NNMultistepModel():def __init__( self, X, Y, n_outputs, n_lag, n_ft, n_layer, batch, epochs, lr, Xval=None, Yval=None, mask_value=-999.0, min_delta=0.001, patience=5 ): lstm_input = Input(shape=(n_lag, n_ft)) # Series signal lstm_layer = LSTM(n_layer, activation='relu')(lstm_input) x = Dense(n_outputs)(lstm_layer) self.model = Model(inputs=lstm_input, outputs=x) self.batch = batch self.epochs = epochs self.n_layer=n_layer self.lr = lr self.Xval = Xval self.Yval = Yval self.X = X self.Y = Y self.mask_value = mask_value self.min_delta = min_delta self.patience = patience def trainCallback(self): return EarlyStopping(monitor='loss', patience=self.patience, min_delta=self.min_delta) def train(self): # Getting the untrained model empty_model = self.model # Initiating the optimizer optimizer = keras.optimizers.Adam(learning_rate=self.lr) # Compiling the model empty_model.compile(loss=losses.MeanAbsoluteError(), optimizer=optimizer) if (self.Xval is not None) & (self.Yval is not None): history = empty_model.fit( self.X, self.Y, epochs=self.epochs, batch_size=self.batch, validation_data=(self.Xval, self.Yval), shuffle=False, callbacks=[self.trainCallback()] ) else: history = empty_model.fit( self.X, self.Y, epochs=self.epochs, batch_size=self.batch, shuffle=False, callbacks=[self.trainCallback()] ) # Saving to original model attribute in the class self.model = empty_model # Returning the training history return history def predict(self, X): return self.model.predict(X)

創建用於建模之前的最後一步是縮放數據。

# Subseting only the needed columns ts = d[features_final]nrows = ts.shape[0]# Spliting into train and test setstrain = ts[0:int(nrows * (1 — test_share))]test = ts[int(nrows * (1 — test_share)):]# Scaling the data train_mean = train.mean()train_std = train.std()train = (train — train_mean) / train_stdtest = (test — train_mean) / train_std# Creating the final scaled frame ts_s = pd.concat([train, test])# Creating the X and Y for trainingX, Y = create_X_Y(ts_s.values, lag=lag, n_ahead=n_ahead)n_ft = X.shape[2]

現在我們將數據分為訓練和驗證

# Spliting into train and test sets Xtrain, Ytrain = X[0:int(X.shape[0] * (1 — test_share))], Y[0:int(X.shape[0] * (1 — test_share))]Xval, Yval = X[int(X.shape[0] * (1 — test_share)):], Y[int(X.shape[0] * (1 — test_share)):]

數據的最終形狀:

Shape of training data: (243863, 48, 7)Shape of the target data: (243863, 1)Shape of validation data: (27096, 48, 7)Shape of the validation target data: (27096, 1)

剩下的就是使用模型類創建對象,訓練模型並檢查驗證集中的結果。

# Initiating the model objectmodel = NNMultistepModel(X=Xtrain, Y=Ytrain, n_outputs=n_ahead, n_lag=lag, n_ft=n_ft, n_layer=n_layer, batch=batch_size, epochs=epochs, lr=lr, Xval=Xval, Yval=Yval,)# Training of the model history = model.train()

使用訓練好的模型,我們可以預測值並將其與原始值進行比較。

# Comparing the forecasts with the actual valuesyhat = [x[0] for x in model.predict(Xval)]y = [y[0] for y in Yval]# Creating the frame to store both predictionsdays = d[『dt』].values[-len(y):]frame = pd.concat([pd.DataFrame({『day』: days, 『temp』: y, 『type』: 『original』}), pd.DataFrame({『day』: days, 『temp』: yhat, 『type』: 『forecast』})])# Creating the unscaled values columnframe[『temp_absolute』] = [(x * train_std[『temp』]) + train_mean[『temp』] for x in frame[『temp』]]# Pivotingpivoted = frame.pivot_table(index=』day』, columns=’type』)pivoted.columns = [『_』.join(x).strip() for x in pivoted.columns.values]pivoted[『res』] = pivoted[『temp_absolute_original』] — pivoted[『temp_absolute_forecast』]pivoted[『res_abs』] = [abs(x) for x in pivoted[『res』]]

結果可視化

plt.figure(figsize=(12, 12))plt.plot(pivoted.index, pivoted.temp_absolute_original, color=』blue』, label=』original』)plt.plot(pivoted.index, pivoted.temp_absolute_forecast, color=’red』, label=』forecast』, alpha=0.6)plt.title(『Temperature forecasts — absolute data』)plt.legend()plt.show()

使用訓練好的模型,我們可以預測值並將其與原始值進行比較。

中位數絕對誤差為0.34攝氏度,平均值為0.48攝氏度。

要預測提前24小時,唯一需要做的就是更改超參數。 具體來說,是n_ahead變量。 該模型將嘗試使用之前(一周)的168小時來預測接下來的24小時值。

# Number of lags (hours back) to use for modelslag = 168# Steps ahead to forecast n_ahead = 24# Share of obs in testing test_share = 0.1# Epochs for trainingepochs = 20# Batch size batch_size = 512# Learning ratelr = 0.001# Number of neurons in LSTM layern_layer = 10# Creating the X and Y for trainingX, Y = create_X_Y(ts_s.values, lag=lag, n_ahead=n_ahead)n_ft = X.shape[2]Xtrain, Ytrain = X[0:int(X.shape[0] * (1 - test_share))], Y[0:int(X.shape[0] * (1 - test_share))]Xval, Yval = X[int(X.shape[0] * (1 - test_share)):], Y[int(X.shape[0] * (1 - test_share)):]# Creating the model object model = NNMultistepModel(X=Xtrain, Y=Ytrain, n_outputs=n_ahead, n_lag=lag, n_ft=n_ft, n_layer=n_layer, batch=batch_size, epochs=epochs, lr=lr, Xval=Xval, Yval=Yval,)# Training the model history = model.train()

檢查一些隨機的24小時區間:

有些24小時序列似乎彼此接近,而其他序列則不然。

平均絕對誤差為1.69 C,中位數為1.27C。

總結,本文介紹了在對時間序列數據進行建模和預測時使用的簡單管道示例:

讀取,清理和擴充輸入數據

為滯後和n步選擇超參數

為深度學習模型選擇超參數

初始化NNMultistepModel()類

擬合模型

預測未來n_steps

最後本文的完整代碼:https://github.com/Eligijus112/Vilnius-weather-LSTM

作者:Eligijus Bujokas

deephub翻譯組

相關焦點

  • 使用LSTM深度學習模型進行溫度的時間序列單步和多步預測
    本文的目的是提供代碼示例,並解釋使用python和TensorFlow建模時間序列數據的思路。本文展示了如何進行多步預測並在模型中使用多個特徵。本文的簡單版本是,使用過去48小時的數據和對未來1小時的預測(一步),我獲得了溫度誤差的平均絕對誤差0.48(中值0.34)度。
  • 乾貨|時間序列預測類問題下的建模方案探索實踐
    隨著機器學習和深度學習的興起,時間序列預測類問題越來越多的被抽象為回歸問題,從而可以使用機器學習和深度學習的相關模型,不需要受到基本假設的限制,適用範圍更廣,更受到人們青睞。本文以疫情期間北京重點區域人群密度情況的預測為例,使用統計學模型ARMA,機器學習模型Xgboost和深度學習模型LSTM分別進行建模,並對這三種建模方案在實際操作時的複雜度、運行效率和預測準確度進行對比分析,從而直觀感受每種建模方案的優缺點,為真實場景中建模方案的選擇提供幫助和參考。
  • 蒙特婁大學開放MILA 2017夏季深度學習與強化學習課程視頻
    有監督機器學習方法可以分為生成方法和判別方法,生成方法學習出的是生成模型,判別方法學習出的是判別模型。生成模型的本質是密度估計(Density Estimation),其基本思想是首先建立樣本的概率密度模型,再利用模型進行推理預測。生成模型的處理過程會告訴你關於數據的一些統計信息(p(x|y) 的分布等),更接近於統計學。
  • 通過Python 代碼實現時間序列數據的統計學預測模型
    來源 | DeepHub IMBA封圖 | CSDN 付費下載於視覺中國在本篇中,我們將展示使用 Python 統計學模型進行時間序列數據分析。 目標是:根據兩年以上的每日廣告支出歷史數據,提前預測兩個月的廣告支出金額。
  • 通過Python 代碼實現時間序列數據的統計學預測模型
    來源 | DeepHub IMBA封圖 | CSDN 付費下載於視覺中國在本篇中,我們將展示使用 Python 統計學模型進行時間序列數據分析。 目標是:根據兩年以上的每日廣告支出歷史數據,提前預測兩個月的廣告支出金額。
  • 機器學習中的時間序列預測概述
    在正常的機器學習問題中,我們通過觀察值來進行預測,預測往往與時間因素無關。在某些情況下,機器學習也可以預測未來的結果,但這將同等對待所有過去的觀察結果。然而,時間序列數據集是完全不同的。移動平均線(MA)與在回歸中使用預測變量的過去值的線性組合不同,移動平均模型通過取該模型中任何觀測子集的平均值來使用過去的預測誤差項(εt)。在此模型中,當前與平均值的偏差取決於過去與平均值的偏差。移動平均線對於預測長期趨勢非常有用。
  • 基於機動LSTM的周圍車輛多模態軌跡預測
    我們提出的LSTM模型允許基於機動類對周圍車輛軌跡進行非線性和多模態預測。它還為每個模式分配了相應概率,並在每個模式周圍輸出了預測的不確定性。本文將機動用於多模態軌跡預測,通過學習一個為不同機動類分配概率的模型,並為每個機動類輸出機動的具體預測。
  • 基於圖卷積神經網絡GCN的時間序列預測
    時間序列預測任務可以按照不同的方法執行。最經典的是基於統計和自回歸的方法。更準確的是基於增強和集成的算法,我們必須使用滾動周期生成大量有用的手工特性。另一方面,我們可以使用在開發過程中提供更多自由的神經網絡模型,提供對順序建模的可定製的特性。循環和卷積結構在時間序列預測中取得了巨大的成功。
  • 金融中的三種深度學習用例及這些模型優劣的證據
    這個模型一旦被識別後就可以從時間序列的過去值及現在值來預測未來值。現代統計方法、計量經濟模型在某種程度上已經能夠幫助企業對未來進行預測。利用整合移動平均自回歸模型,來嘗試預測季節性平穩時間序列,我們得到結果如下圖所示:
  • 氣象預測:從物理過程到深度學習
    大氣的氣溫變化受很多因素(輻射,空氣運動等)的影響,在物理模型中通常使用對流擴散過程來對大氣的溫度變化進行建模,方程如下所示:航空智慧氣象創新中心所提出的PGnet模型結構圖如下,為了充分利用物理過程和神經網絡的優勢,主要結構分為前部分的物理過程部分和後部分的神經網絡生成部分。
  • 「乾貨」深入淺出LSTM及其Python代碼實現
    歷史上神經網絡的發展大致經歷了三次高潮:20世紀40年代的控制論、20世紀80年代到90年代中期的聯結主義和2006年以來的深度學習。因此,我們需要構建具有「記憶」能力的神經網絡模型,用來處理需要理解上下文意思的信號,也就是時間序列數據。循環神經網絡(RNN)就是用來處理這類信號的,RNN之所以能夠有效的處理時間序列數據,主要是基於它比較特殊的運行原理。下面將介紹RNN的構建過程和基本運行原理,然後引入長短期記憶網絡(LSTM)。2.
  • 通過深度學習來創作自己的音樂(附代碼)
    直到我遇到了深度學習。使用特定的技術和框架,我可以創作自己的原創音樂,而不需要真正了解任何音樂理論!這是我最喜歡的專業項目之一。我把我的兩個愛好——音樂和深度學習——結合起來,創造了一個自動生成音樂的模型。夢想成真了!我很高興與你分享我的方法,包括整個代碼,使你能夠生成自己的音樂!
  • 「深度學習」運用多通道亞結構圖進行分子性質預測
    隨著人工智慧技術的發展,深度學習方法在藥物分子設計中的應用愈發廣泛。分子性質的預測在藥物發現過程中起著很大作用。為了對分子性質進行預測,首先需要對分子進行表徵。應用深度學習對分子進行表徵有多種途徑,例如SMILES將分子編碼成一個字符串序列,根據成環結構斷開的位置不同,同一分子可能得到不同的SMILES。
  • 機器翻譯:谷歌翻譯是如何對幾乎所有語言進行翻譯的?
    它使用人工神經網絡來預測某個單詞序列的概率,通常在單個集成模型中對整個句子進行建模。憑藉神經網絡的強大功能,神經網絡機器翻譯已經成為翻譯領域最強大的算法。這種最先進的算法是深度學習的一項應用,其中大量已翻譯句子的數據集用於訓練能夠在任意語言對之間的翻譯模型。
  • 機器翻譯:谷歌翻譯是如何對幾乎所有語言進行翻譯的?
    它使用人工神經網絡來預測某個單詞序列的概率,通常在單個集成模型中對整個句子進行建模。憑藉神經網絡的強大功能,神經網絡機器翻譯已經成為翻譯領域最強大的算法。這種最先進的算法是深度學習的一項應用,其中大量已翻譯句子的數據集用於訓練能夠在任意語言對之間的翻譯模型。
  • 「深度學習」運用多通道亞結構圖進行分子性質預測
    隨著人工智慧技術的發展,深度學習方法在藥物分子設計中的應用愈發廣泛。分子性質的預測在藥物發現過程中起著很大作用。為了對分子性質進行預測,首先需要對分子進行表徵。應用深度學習對分子進行表徵有多種途徑,例如SMILES將分子編碼成一個字符串序列,根據成環結構斷開的位置不同,同一分子可能得到不同的SMILES。
  • Meal Kit 的時間序列數據預測實踐
    在時間序列中,缺失的數據可能會隱藏起來,因為數據可能在時間步長(1周)內不一致,這將在構建模型時可能會導致問題。對每個供應中心標識的數據進行分組。其中一些食材並非每周訂購/提供的,那麼將這幾周的需求量取為0,但是價格設置為組內食材的平均值。我們假設這些食材在缺失的幾周內是有提供的,但是沒有人買。在研究了餐盒市場後,人們意識到大部分成本來自易腐商品。
  • 「深度學習」通過學習勢能函數實現蛋白質的結構預測
    然而在很多情況下,蛋白質的三維結構信息是難以獲得的,因此有必要藉助基於理論計算的方法對其結構進行預測。深度神經網絡(DNN)近期在蛋白質結構預測方面展現出了優異的表現,該領域常用的方法包括(1)胺基酸殘基間距預測(參考:AlphaFold開啟了新方向嗎)以及(2)相鄰殘基間的扭轉角預測(參考:最新蛋白結構預測模型-循環幾何網絡RGN),這些方法在往期的推送中都有所涉及。
  • 【天池大賽·追風】颱風圖像時間序列預測
    我們相信, 即使沒有獎金這個賽事的意義與數據也同樣有吸引力在太平洋西側,每年夏季會陸續生成一系列熱帶風暴其中有些發展成為颱風乃至於超級颱風一邊旋轉一邊向亞洲東海岸移動颱風往往在東南亞國家、中國、日本、以及朝鮮半島登陸帶來狂風暴雨, 造成巨大的財產損失,時有人員傷亡如果能夠提早一兩天預測到
  • 六種方法解決LSTM循環神經網絡中的超長序列問題
    長短期記憶(LSTM)循環神經網絡可以學習和記憶長段序列的輸入。如果你的問題對於每個輸入都有一個輸出(如時間序列預測和文本翻譯任務),那麼 LSTM 可以運行得很好。但 LSTM 在面臨超長輸入序列——單個或少量輸出的情形時就會遇到困難了。這種問題通常被稱為序列標記,或序列分類。