跳到主要內容

程式 DIY|for 時間序列預測的小工具


IT 工程師的圈子內有個俚語,大意是:「如果已經有人把輪子造出來了,那何必再自己造一次輪子?」,輪子指的即是工具。先撇開程式運作效率以及彈性不談,如果過去已經有人把我們要的功能給寫出來了,且這段程式碼我們也能夠正常取得的化,那我們何必在自己寫一次?這對當今廣義的程式開發工作者而言,是很理所當然的事情。但是反過來說,如果今天我們想要的功能,還沒有人寫出來(當然也有可能是我們不夠神通廣大,沒在公開環境當中找到符合我們需求的玩意兒),那麼自己寫一套,也是很正常的,而這個系列的宗旨即是如此。

在這篇文章之前,筆者已經放了四篇不太好消化的領域知識探討文章。所以這一篇我們就換換口味,談談好久沒提到的程式設計。說是這麼說,但本文所要分享的東西,其實都與過去幾篇「時間序列」主題的文章相關,而些程式碼都放在筆者自己建立的 GitHub repository 當中,裏頭包含了三個 .py 檔,每一個 .py 檔主都是一個簡單的自定義函數。以下分別介紹:


# series_rescaler

如函數名稱,「序列的正規化」,其功能是將餵進函數的 Python 數值資料list,依照指定的長短期數(int),進行等比例的長度縮放以及將原始 list 的各期數值給正規化,其正規化的 list 各期數值加總為 1。這項功能要應用於【淺談供應鏈需求預測】的第四篇文章「產品生命週期」的相關應用當中。在比較不同長度以及總和數量不同的序列資料,勢必比較基準也得一致才行,而這道函數的功能便是執行了這項前處理功能。

讀著們會好奇,正規化?那麼我能將原本較長的序列資料縮短、也能將原本較短的序列資料拉長嗎?當然,這道函數的功能變是如此,它的原理就是將原本各期的數值資料進行「加總為 1 的正規化處理」後,再依照新的指定期數長短進行等比例的劃分,再依序塞到對應的新位置(即正規化後的新的 list 的 item 順序)當中。而由於前面的步驟已經先經過了「加總為 1 的正規化處理」,所以縮放之後的序列資料,也保有原本的數量比例分佈。惟須留意的是,由於縮放後的各期數字是以迴圈逐項計算的,由於浮點數計算的因素,有可能使縮放後的序列資料加總不完全等於 1,可能有個正負 0.001 之類的浮點數運算差異。如果是非常在乎精準度的使用者,請務必將縮放後的序列資料再檢查一次加總是否剛好為 1。


# sim_calculator

這道函數是功能是計算餵進函數的兩條 Python 數值資料 list 之間的相似度,最大為 1 最小為 0。由於其預設接收到的兩條 list 的長度一致,因此實際使用時通常要與前面提到的 series_rescaler() 相互搭配使用。最初寫出這道函數的用意,就是為了計算「產品生命週期曲線的相似度」。計算時間序列資料相似度的方法有很多種(例如文章開頭所引用的圖片當中 show 的三種),但為何要採用這篇論文提到的計算方法呢?那是因為,該論文所提出來的相似度計算概念能夠挪用於逐期累積百分比相似性比較上,這是其他的時間序列相似度計算方法所謂考量的特性。


# grey_forecasting

最後一道函數是「灰預測模型」,是灰色系統理論 (Grey System Theory)的其中一項旁支應用。相信不少工程、管理學科背景的讀者們,在就讀碩博士班的時候,或多或少接觸過這項方法論,其跟模糊理論(Fuzzy Logic)一樣,算是已經被學術界玩到爛的東西,假設灰預測模型具有一定的實用性,那麼經過 30 年(灰色系統理論在西元 1990 年之前就被提出了)的考驗後,其地位應該要跟 ARIMAETS 等經典模型一樣,是作為一個時間序列預測的常用基礎模型才是。但是,可能是我見識短少,我在 Python 社群常用的統計與計量分析工具包如 statsmodelsScipy 當中,沒有看到灰預測模型被放上去。筆者猜想,其實用性不及 ARIMA 與 ETS,可能就是灰預測模型沒被放入這些常用工具包的其中一項原因。但是沒關係,灰預測模型背後的數學原理並不難,而且我們是要拿它來作為預測成效比較的 baseline model。既然常用工具包裏頭沒有,那就自己動手刻一個吧!而除了我自己手寫的版本之外,亦可以參考其他網友自行撰寫的版本


文章開頭的引用圖片來源:
Joan Serrà & Josep Lluis Arcos. (2014). An Empirical Evaluation of Similarity Measures for Time Series Classification.  arXiv preprint arXiv: 1401.3973.