您好,登錄后才能下訂單哦!
這篇文章主要介紹了Python基于LightGBM進行時間序列預測的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
當我們考慮時間序列的增強樹時,通常會想到 M5 比賽,其中前十名中有很大一部分使用了 LightGBM。但是當在單變量情況下使用增強樹時,由于沒有大量的外生特征可以利用,它的性能非常的糟糕。
首先需要明確的是M4 比賽的亞軍 DID 使用了增強樹。但是它作為一個元模型來集成其他更傳統的時間序列方法。在 M4 上公開的代碼中,所有標準增強樹的基準測試都相當糟糕,有時甚至還達不到傳統的預測方法。下面是Sktime 包和他們的論文所做的出色工作:
任何帶有“XGB”或“RF”的模型都使用基于樹的集成。在上面的列表中 Xgboost 在每小時數據集中提供了 10.9 的最佳結果!然后,但是這些模型只是Sktime 在他們框架中做過的簡單嘗試,而 M4 的獲勝者在同一數據集上的得分是 9.3 分……。在該圖表中我們需要記住一些數字,例如來自 XGB-s 的每小時數據集的 10.9 和每周數據集中的樹性模型的“最佳”結果:來自 RF-t-s 的 9.0。
從上圖中就引出了我們的目標:創建一個基于LightGBM并且適合個人使用的時間序列的快速建模程序,并且能夠絕對超越這些數字,而且在速度方面可與傳統的統計方法相媲美。
聽起來很困難,并且我們的第一個想法可能是必須優化我們的樹。但是提升樹非常復雜,改動非常費時,并且結果并不一定有效。但是有一點好處是我們正在擬合是單個數據集,是不是可從特征下手呢?
在查看單變量空間中樹的其他實現時都會看到一些特征工程,例如分箱、使用目標的滯后值、簡單的計數器、季節性虛擬變量,也許還有傅里葉函數。這對于使用傳統的指數平滑等方法是非常棒的。但是我們今天目的是必須對時間元素進行特征化并將其表示為表格數據以提供給樹型模型,LazyProphet這時候就出現了。除此以外,LazyProphet還包含一個額外的特征工程元素:將點”連接”起來。
很簡單,將時間序列的第一個點連接起來,并將一條線連接到中途的另一個點,然后將中途的點連接到最后一個點。重復幾次,同時更改將哪個點用作“kink”(中間節點),這就是我們所說的“連接”。
下面張圖能很好地說明這一點。藍線是時間序列,其他線只是“連接點”:
事實證明,這些只是加權分段線性基函數。這樣做的一個缺點是這些線的外推可能會出現偏差。為了解決這個問題,引入一個懲罰從中點到最后點的每條線的斜率的“衰減”因子。
在這個基礎上加滯后的目標值和傅里葉基函數,在某些問題上就能夠接近最先進的性能。因為要求很少,因因此我們把它稱作“LazyProphet”。
下面我們看看實際的應用結果。
這里使用的數據集都是開源的,并在M-competitions github上發布。數據已經被分割為訓練和測試集,我們直接使用訓練csv進行擬合,而測試csv用于使用SMAPE進行評估。現在導入LazyProphet:
pip install LazyProphet
安裝后,開始編碼:
import matplotlib.pyplot as plt import numpy as np from tqdm import tqdm import pandas as pd from LazyProphet import LazyProphet as lp train_df = pd.read_csv(r'm4-weekly-train.csv') test_df = pd.read_csv(r'm4-weekly-test.csv') train_df.index = train_df['V1'] train_df = train_df.drop('V1', axis = 1) test_df.index = test_df['V1'] test_df = test_df.drop('V1', axis = 1)
導入所有必要的包后將讀入每周數據。創建 SMAPE 函數,它將返回給定預測和實際值的 SMAPE:
def smape(A, F): return 100/len(A) * np.sum(2 * np.abs(F - A) / (np.abs(A) + np.abs(F)))
對于這個實驗將取所有時間序列的平均值與其他模型進行比較。為了進行健全性檢查,我們還將獲得的平均 SMAPE,這樣可以確保所做的與比賽中所做的一致。
smapes = [] naive_smape = [] j = tqdm(range(len(train_df))) for row in j: y = train_df.iloc[row, :].dropna() y_test = test_df.iloc[row, :].dropna() j.set_description(f'{np.mean(smapes)}, {np.mean(naive_smape)}') lp_model = LazyProphet(scale=True, seasonal_period=52, n_basis=10, fourier_order=10, ar=list(range(1, 53)), decay=.99, linear_trend=None, decay_average=False) fitted = lp_model.fit(y) predictions = lp_model.predict(len(y_test)).reshape(-1) smapes.append(smape(y_test.values, pd.Series(predictions).clip(lower=0))) naive_smape.append(smape(y_test.values, np.tile(y.iloc[-1], len(y_test)))) print(np.mean(smapes)) print(np.mean(naive_smape))
在查看結果之前,快速介紹一下 LazyProphet 參數。
scale:這個很簡單,只是是否對數據進行縮放。默認值為 True 。
seasonal_period:此參數控制季節性的傅立葉基函數,因為這是我們使用 52 的每周頻率。
n_basis:此參數控制加權分段線性基函數。這只是要使用的函數數量的整數。
Fourier_order:用于季節性的正弦和余弦對的數量。
ar:要使用的滯后目標變量值。可以獲取多個列表 1-52 。
decay:衰減因子用于懲罰我們的基函數的“右側”。設置為 0.99 表示斜率乘以 (1- 0.99) 或 0.01。
linear_trend:樹的一個主要缺點是它們無法推斷出后續數據的范圍。為了克服這個問題,有一些針對多項式趨勢的現成測試將擬合線性回歸以消除趨勢。None 表示有測試,通過 True 表示總是去趨勢,通過 False 表示不測試并且不使用線性趨勢。
decay_average:在使用衰減率時不是一個有用的參數。這是一個trick但不要使用它。傳遞 True 只是平均基函數的所有未來值。這在與 elasticnet 程序擬合時很有用,但在測試中對 LightGBM 的用處不大。
下面繼續處理數據:
train_df = pd.read_csv(r'm4-hourly-train.csv') test_df = pd.read_csv(r'm4-hourly-test.csv') train_df.index = train_df['V1'] train_df = train_df.drop('V1', axis = 1) test_df.index = test_df['V1'] test_df = test_df.drop('V1', axis = 1) smapes = [] naive_smape = [] j = tqdm(range(len(train_df))) for row in j: y = train_df.iloc[row, :].dropna() y_test = test_df.iloc[row, :].dropna() j.set_description(f'{np.mean(smapes)}, {np.mean(naive_smape)}') lp_model = LazyProphet(seasonal_period=[24,168], n_basis=10, fourier_order=10, ar=list(range(1, 25)), decay=.99) fitted = lp_model.fit(y) predictions = lp_model.predict(len(y_test)).reshape(-1) smapes.append(smape(y_test.values, pd.Series(predictions).clip(lower=0))) naive_smape.append(smape(y_test.values, np.tile(y.iloc[-1], len(y_test)))) print(np.mean(smapes)) print(np.mean(naive_smape))
所以真正需要修改是seasonal_period 和ar 參數。將list傳遞給seasonal_period 時,它將為列表中的所有內容構建季節性基函數。ar 進行了調整以適應新的主要季節 24。
對于上面的 Sktime 結果,表格如下:
LazyProphet 擊敗了 Sktime 最好的模型,其中包括幾種不同的基于樹的方法。在每小時數據集上輸給給了 M4 的獲勝者,但平均而言總體上優于 ES-RNN。這里要意識到的重要一點是,只使用默認參數進行了此操作……
boosting_params = { "objective": "regression", "metric": "rmse", "verbosity": -1, "boosting_type": "gbdt", "seed": 42, 'linear_tree': False, 'learning_rate': .15, 'min_child_samples': 5, 'num_leaves': 31, 'num_iterations': 50 }
可以在創建 LazyProphet 類時傳遞你參數的字典,可以針對每個時間序列進行優化,以獲得更多收益。
對比一下我們的結果和上面提到的目標:
進行了零參數優化(針對不同的季節性稍作修改)
分別擬合每個時間序列
在我的本地機器上在一分鐘內“懶惰地”生成了預測。
在基準測試中擊敗了所有其他樹方法
目前看是非常成功的,但是成功可能無法完全的復制,因為他數據集的數據量要少得多,因此我們的方法往往會顯著降低性能。根據測試LazyProphet 在高頻率和大量數據量上表現的更好,但是LazyProphet還是一個時間序列建模的很好選擇,我們不需要花多長時間進行編碼就能夠測試,這點時間還是很值得。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“Python基于LightGBM進行時間序列預測的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。