- 1、Pandas-時間序列基礎
- 2、用Python預測「周期性時間序列」的正確姿勢
- 3、時間序列分析方法
Python標準庫中包含用於日期和時間的數據類型,而且還有日曆方面的功能,我們主要會用到datetime、time和calendar模塊,datetime.datetime是用的最多的數據類型。
datetime以毫秒形式存儲日期和時間,datetime.timedelta表示兩個datetime對象之間的時間差.
可以給datetime對象加上或者減去一個或多個timedelta,會產生一個新對象:
利用str或者strftime方法,datetime對象和pandas的Timestamp對象可以被格式化為字符串:
datetime.strptime也可以用這些格式化編碼將字符串轉化為日期:
datetime.strptime是通過已知格式進行日期解析的最佳方式,但是每次都要編寫格式定義很麻煩,尤其是對於一些常見的日期格式,這種情況下,可以用dateutil這個第三方包中的parser.parse方法,dateutil可以解析幾乎所有人類能夠理解的日期表示形式:
在國際通用格式中,日通常出現在月的前面,傳入dayfirst=True即可:
pandas通常是用於處理成組日期的,不管這些日期是DataFrame的軸索引還是列,to_datetime方法可以解析多種不同的日期表示形式。
to_datetime可以處理缺失值,NAT是pandas中時間戳數據的NA值:
pandas最基本的時間序列類型就是以時間戳為索引的Series:
這裡的Series索引不是普通的索引,而是DatetimeIndex,而ts變為了一個TimeSeries,同時,可以看到,pandas用Numpy的datetime64數據類型以納秒形式存儲時間戳。
跟其他Series一樣,不同索引的時間序列之間的算數運算會自動對齊:
DateTimeIndex中的各個標量值是pandas的Timestamp對象.
由於TimeSeries是Series的一個子類,所以在索引以及數據選曲方面他們的行為是一樣的,但是我們還可以傳入一個可以被解釋為日期的字符串來進行索引:
對於較長的時間序列,只需傳入年或年月即可輕鬆選取數據的切片:
通過日期進行切片的方式只對規則Series有效:
還有一個等價的實例方法也可以截取兩個日期之間的TimeSeries:
DataFrame也同樣適用上面的規則
pandas中的時間序列一般被認為是不規則的,也就是說,沒有固定的頻率,對於大部分程序而言,這是無所謂的,但是,他常常需要以某種相對固定的頻率進行分析,比如每月,每日,每15min等。pandas有一套標準時間序列頻率以及用於重採樣,頻率推斷,生成固定頻率日期範圍的工具.
例如,我們可以將之前的時間序列轉換為一個具有固定頻率(每日)的時間序列,只需調用resample即可.返回DatetimeIndexResampler,獲取值使用asfreq():
生成日期範圍使用date_range函數
默認情況下,date_range會產生按天計算的時間點,如果只傳入起始或結束日期,那就還得傳入一個表示一段時間的數字:
如果你不想按天生成數據,想要按照一定的頻率生成,我們傳入freq參數即可.如想按5小時生成數據:
如果你想生成一個由每月最後一個工作日組成的日期索引,可以使用BM頻率:
date_range默認會保留起始和結束的時間戳的時間信息,但是如果我們想產生一組規範化到午夜的時間戳,normalize選項可以實現這個功能:
WOM(week of Month)是一種非常實用的頻率類,它以WOM開頭,它使你能獲得諸如每月第三個星期五之類的日期:
公司平台上有不同的api,供內部或外部調用,這些api承擔著不同的功能,如查詢賬號、發版、搶紅包等等。日誌會記錄下每分鐘某api被訪問了多少次,即一個api每天會有1440條記錄(1440分鐘),將每天的數據連起來觀察,有點類似於股票走勢的意思。我想通過前N天的歷史數據預測出第N+1天的流量訪問情況,預測值即作為合理參考,供新一天與真實值做實時對比。當真實流量跟預測值有較大出入,則認為有異常訪問,觸發報警。
我放了一份樣例數據在data文件夾下,
看一下數據大小和結構
畫圖看一下序列的走勢:(一些畫圖等探索類的方法放在了test_stationarity.py 文件中,包含時間序列圖,移動平均圖,有興趣的可以自己嘗試下)。
看這糟心的圖,那些驟降為0的點這就是我遇到的第一個坑,我當初一拿到這份數據就開始做了。後來折騰了好久才發現,那些驟降為0的點是由於數據缺失,ETL的同學自動補零造成的,溝通晚了(TДT)。
把坑填上,用前後值的均值把缺失值補上,再看一眼:
發現這份數據有這樣幾個特點,在模型設計和數據預處理的時候要考慮到:
前六天的數據做訓練,第七天做測試集。
消除數據的毛刺,可以用移動平均法,我這裡沒有採用,因為我試過發現對於我的數據來說,移動平均處理完後並不能使數據平滑,我這裡採用的方法很簡單,但效果還不錯:把每個點與上一點的變化值作為一個新的序列,對這裡邊的異常值,也就是變化比較離譜的值剃掉,用前後數據的均值填充,注意可能會連續出現變化較大的點:
平滑後的訓練數據:
採用statsmodels工具包:
對分解出來的趨勢部分單獨用arima模型做訓練:
預測出趨勢數據後,加上周期數據即作為最終的預測結果,但更重要的是,我們要得到的不是具體的值,而是一個合理區間,當真實數據超過了這個區間,則觸發報警,誤差高低區間的設定來自剛剛分解出來的殘差residual數據:
預測並完成最後的加法處理,得到第七天的預測值即高低置信區間:
對第七天作出預測,評估的指標為均方根誤差rmse,畫圖對比和真實值的差距:
可以看到,均方根誤差462.8,相對於原始數據幾千的量級,還是可以的。測試數據中的兩個突變的點,也超過了置信區間,能準確報出來。
前文提到不同的api形態差異巨大,本文只展示了一個,我在該項目中還接觸了其他形態的序列,有的有明顯的上升或下降趨勢;有的開始比較平緩,後面開始增長… … ,但是都屬於典型的周期性時間序列,它的核心思想很簡單:做好分解,做好預測結果的還原,和置信區間的設置,具體操作可根據具體業務邏輯做調整,祝大家建模愉快:-D。
時間序列是指一組在連續時間上測得的數據,其在數學上的定義是一組向量x(t), t=0,1,2,3,…,其中t表示數據所在的時間點,x(t)是一組按時間順序(測得)排列的隨機變量。包含單個變量的時間序列稱為單變量時間序列,而包含多個變量的時間序列則稱為多變量。
時間序列在很多方面多有涉及到,如天氣預報,每天每個小時的氣溫,股票走勢等等,在商業方面有諸多應用,如:
下面我們將通過一個航班數據來說明如何使用已有的工具來進行時間序列數據預測。常用來處理時間序列的包有三個:
對於基於AR、MA的方法一般需要數據預處理,因此本文分為三部分:
通過簡單的初步處理以及可視化可以幫助我們有效快速的了解數據的分布(以及時間序列的趨勢)。
觀察數據的頻率直方圖以及密度分布圖以洞察數據結構,從下圖可以看出:
使用 statsmodels 對該時間序列進行分解,以了解該時間序列數據的各個部分,每個部分都代表着一種模式類別。借用 statsmodels 序列分解我們可以看到數據的主要趨勢成分、季節成分和殘差成分,這與我們上面的推測相符合。
如果一個時間序列的均值和方差隨着時間變化保持穩定,則可以說這個時間序列是穩定的。
大多數時間序列模型都是在平穩序列的前提下進行建模的。造成這種情況的主要原因是序列可以有許多種(複雜的)非平穩的方式,而平穩性只有一種,更加的易於分析,易於建模。
在直覺上,如果一段時間序列在某一段時間序列內具有特定的行為,那麼將來很可能具有相同的行為。譬如已連續觀察一個星期都是六點出太陽,那麼可以推測明天也是六點出太陽,誤差非常小。
而且,與非平穩序列相比,平穩序列相關的理論更加成熟且易於實現。
一般可以通過以下幾種方式來檢驗序列的平穩性:
如果時間序列是平穩性的,那麼在ACF/PACF中觀測點數據與之前數據點的相關性會急劇下降。
下圖中的圓錐形陰影是置信區間,區間外的數據點說明其與觀測數據本身具有強烈的相關性,這種相關性並非來自於統計波動。
PACF在計算X(t)和X(t-h)的相關性的時候,挖空在(t-h,t)上所有數據點對X(t)的影響,反應的是X(t)和X(t-h)之間真實的相關性(直接相關性)。
從下圖可以看出,數據點的相關性並沒有急劇下降,因此該序列是非平穩的。
如果序列是平穩的,那麼其滑動均值/方差會隨着時間的變化保持穩定。
但是從下圖我們可以看到,隨着時間的推移,均值呈現明顯的上升趨勢,而方差也呈現出波動式上升的趨勢,因此該序列是非平穩的。
一般來講p值小於0.05我們便認為其是顯著性的,可以拒絕零假設。但是這裡的p值為0.99明顯是非顯著性的,因此接受零假設,該序列是非平穩的。
從上面的平穩性檢驗我們可以知道該時間序列為非平穩序列。此外,通過上面1.3部分的序列分解我們也可以看到,該序列可分解為3部分:
我們可以使用數據轉換來對那些較大的數據施加更大的懲罰,如取對數、開平方根、立方根、差分等,以達到序列平穩的目的。
滑動平均後數據失去了其原來的特點(波動式上升),這樣損失的信息過多,肯定是無法作為後續模型的輸入的。
差分是常用的將非平穩序列轉換平穩序列的方法。ARIMA中的 ‘I’ 便是指的差分,因此ARIMA是可以對非平穩序列進行處理的,其相當於先將非平穩序列通過差分轉換為平穩序列再來使用ARMA進行建模。
一般差分是用某時刻數值減去上一時刻數值來得到新序列。但這裡有一點區別,我們是使用當前時刻數值來減去其對應時刻的滑動均值。
我們來看看剛剛差分的結果怎麼樣。
讓我們稍微總結下我們剛剛的步驟:
通過上面的3步我們成功的將一個非平穩序列轉換成了一個平穩序列。上面使用的是最簡單的滑動均值,下面我們試試指數滑動平均怎麼樣。
上面是最常用的指數滑動平均的定義,但是pandas實現的指數滑動平均好像與這個有一點區別,詳細區別還得去查pandas文檔。
指數滑動均值的效果看起來也很差。我們使用差分+指數滑動平均再來試試吧。
在上面我們通過 取log+(指數)滑動平均+差分 已經成功將非平穩序列轉換為了平穩序列。
下面我們看看,轉換後的平穩序列的各個成分是什麼樣的。不過這裡我們使用的是最簡單的差分,當前時刻的值等於原始序列當前時刻的值減去原始序列中上一時刻的值,即: x'(t) = x(t) – x(t-1)。
看起來挺不錯,是個平穩序列的樣子。不過,還是檢驗一下吧。
可以看到,趨勢(Trend)部分已基本被去除,但是季節性(seasonal)部分還是很明顯,而ARIMA是無法對含有seasonal的序列進行建模分析的。
在一開始我們提到了3個包均可以對時間序列進行建模。
為了簡便,這裡 pmdarima 和 statsmodels.tsa 直接使用最好的建模方法即SARIMA,該方法在ARIMA的基礎上添加了額外功能,可以擬合seasonal部分以及額外添加的數據。
在使用ARIMA(Autoregressive Integrated Moving Average)模型前,我們先簡單了解下這個模型。這個模型其實可以包括三部分,分別對應着三個參數(p, d, q):
因此ARIMA模型就是將AR和MA模型結合起來然後加上差分,克服了不能處理非平穩序列的問題。但是,需要注意的是,其仍然無法對seasonal進行擬合。
下面開始使用ARIMA來擬合數據。
(1) 先分訓練集和驗證集。需要注意的是這裡使用的原始數據來進行建模而非轉換後的數據。
(2)ARIMA一階差分建模並預測
(3)對差分結果進行還原
先手動選擇幾組參數,然後參數搜索找到最佳值。需要注意的是,為了避免過擬合,這裡的階數一般不太建議取太大。
可視化看看結果怎麼樣吧。
(6)最後,我們還能對擬合好的模型進行診斷看看結果怎麼樣。
我們主要關心的是確保模型的殘差(residual)部分互不相關,並且呈零均值正態分布。若季節性ARIMA(SARIMA)不滿足這些屬性,則表明它可以進一步改善。模型診斷根據下面的幾個方面來判斷殘差是否符合正態分布:
同樣的,為了方便,我們這裡使用 pmdarima 中一個可以自動搜索最佳參數的方法 auto_arima 來進行建模。
一般來說,在實際生活和生產環節中,除了季節項,趨勢項,剩餘項之外,通常還有節假日的效應。所以,在prophet算法裡面,作者同時考慮了以上四項,即:
上式中,
更多詳細Prophet算法內容可以參考 Facebook 時間序列預測算法 Prophet 的研究 。
Prophet算法就是通過擬合這幾項,然後把它們累加起來得到時間序列的預測值。
Prophet提供了直觀且易於調整的參數:
Prophet對輸入數據有要求:
關於 Prophet 的使用例子可以參考 Prophet example notebooks
下面使用 Prophet 來進行處理數據。
參考:
Facebook 時間序列預測算法 Prophet 的研究
Prophet example notebooks
auto_arima documentation for selecting best model
數據分析技術:時間序列分析的AR/MA/ARMA/ARIMA模型體系
時間序列分析
My First Time Series Comp (Added Prophet)
Prophet官方文檔:
原創文章,作者:PB6HP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/127233.html