Python 時間序列分析
時間序列簡介
時間序列分析是資料分析過程中,尤其是在金融資料分析過程中會經常遇到的。時間序列,就是以時間排序的一組隨機變數,例如國家統計局每年或每月定期釋出的 GDP 或 CPI 指數;24 小時內某一股票、基金、指數的數值變化等,都是時間序列。
下圖擷取自雅虎財經網站,它就是納斯達克指數某一天內數值變化(時間序列)的視覺化結果。
時間序列處理
我們拿到一些時間序列原始資料時,可能會遇到下面的一些情況:
某一段時間缺失,需要填充。
時間序列錯位,需要對齊。
資料表 a 和資料表 b 所採用的時間間隔不一致,需要重新取樣。
……
面對這些問題,我們就要通過一些處理手段來獲得最終想要的資料。本節課程中,我們會繼續用到 Pandas 提供的時間序列處理模組,下面先看一些基本的方法和操作。
目前,Pandas 針對時間序列處理的類和方法如下:
我們按照順序來看一看這些方法可以做什麼。
Timestamp 時間戳
時間戳,即代表一個時間時刻。我們可以直接用 pd.Timestamp()來建立時間戳。我們使用 ipython 演示,在重點中通過 anaconda/bin/ipython 開啟。(小提示:使用 ipython 時,可以通過 Tab 鍵完成程式碼自動補全。)
In [1]: import pandas as pd
In [2]: pd.Timestamp("2017-1-1")
Out[2]: Timestamp('2017-01-01 00:00:00')
In [3]: pd.Timestamp(2017,10,1)
Out[3]: Timestamp('2017-10-01 00:00:00')
In [4]: pd.Timestamp("2017-1-1 12:59:59")
Out[4]: Timestamp('2017-01-01 12:59:59')
時間戳索引
我們可以看到,單個時間戳為 Timestamp 資料,而時間戳以列表形式存在時,Pandas 將強制轉換為 DatetimeIndex。此時,我們就不能再使用 pd.Timestamp()來建立時間戳了,而是 pd.to_datetime()來建立:
In [6]: pd.to_datetime(["2017-1-1","2017-1-2","2017-1-3"])
Out[6]: DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], dtype='datetime64[ns]', freq=None)
注意輸出部分和上面的區別。
pd.to_datetime() 不僅僅可用來建立 DatetimeIndex,它還可以將對時間戳序列格式進行轉換等操作。例如下面,常見的時間戳書寫樣式,都可以通過pd.to_datetime() 規範化。
In [7]: pd.to_datetime(['Jul 1, 2017', '2017-10-10', None])
Out[7]: DatetimeIndex(['2017-07-01', '2017-10-10', 'NaT'], dtype='datetime64[ns]', freq=None)
In [8]: pd.to_datetime(['2017/10/1', '2017.1.31'])
Out[8]: DatetimeIndex(['2017-10-01', '2017-01-31'], dtype='datetime64[ns]', freq=None)
對於歐洲時區普遍採用的書寫樣式,我們還可以通過 dayfirst=True 引數進行修正:
In [11]: pd.to_datetime('1-10-2017')
Out[11]: Timestamp('2017-01-10 00:00:00')
In [12]: pd.to_datetime('1-10-2017', dayfirst=True)
Out[12]: Timestamp('2017-10-01 00:00:00')
當然,Pandas 所熟悉的 Seris 和 DataFrame 格式的字串,也可以直接通過 to_datetime 轉換:
In [15]: pd.to_datetime(pd.Series(['2017-1-1', '2017-1-2', '2017-1-3']))
Out[15]:
0 2017-01-01
1 2017-01-02
2 2017-01-03
dtype: datetime64[ns]
In [16]: pd.to_datetime(['2017-1-1', '2017-1-2', '2017-1-3'])
In [16]: DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], dtype='datetime64[ns]', freq=None)
In [17]: pd.to_datetime(pd.DataFrame({'year': [2017, 2017], 'month': [1, 2], 'day': [3, 4], 'hour': [5, 6]}))
Out[17]:
0 2017-01-03 05:00:00
1 2017-02-04 06:00:00
dtype: datetime64[ns]
其中:
pd.to_datetime(Series/DataFrame)返回的是Series。
pd.to_datetime(List)返回的是DatetimeIndex。
如果要轉換如上所示的DataFrame,必須存在的列名有year,month,day。另外 hour, minute, second, millisecond, microsecond, nanosecond可選。
當我們在使用pd.to_datetime() 轉換資料時,很容易遇到無效資料。有一些任務對無效資料非常苛刻,所以報錯讓我們找到這些無效資料是不錯的方法。當然,也有一些任務不在乎零星的無效資料,這時候就可以選擇忽略。
遇到無效資料包錯
In [17]: pd.to_datetime(['2017-1-1', 'invalid'], errors='raise')
ValueError: Unknown string format
忽略無效資料
In [18]: pd.to_datetime(['2017-1-1', 'invalid'], errors='ignore')
Out[18]: array(['2017-1-1', 'invalid'], dtype=object)
將無效資料顯示為 NaT
In [19]: pd.to_datetime(['2017-1-1', 'invalid'], errors='coerce')
Out[19]: DatetimeIndex(['2017-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
接下來,我們看一看生成 DatetimeIndex 的另一個重要方法 pandas.data_range。你應該可以從名字看出該方法的作用,我們可以通過指定一個規則,讓 pandas.data_range 生成有序的 DatetimeIndex。
pandas.data_range 方法帶有的預設引數如下:
pandas.date_range(start=None, end=None, periods=None, freq=’D’, tz=None, normalize=False,
name=None, closed=None, **kwargs)
常用引數的含義如下:
start= :設定起始時間
end=:設定截至時間
periods= :設定時間區間,若 None 則需要設定單獨設定起止和截至時間。
freq= :設定間隔週期。
tz=:設定時區。
其中,freq= 引數是非常關鍵的引數,我們可以設定的週期有:
freq='s': 秒
freq='min' : 分鐘
freq='H': 小時
freq='D': 天
freq='w': 周
freq='m': 月
freq='BM': 每個月最後一天
freq='W':每週的星期日
# 從 2017-1-1 到 2017-1-2,以小時間隔
In [21]: pd.date_range('2017-1-1','2017-1-2',freq='H')
Out[21]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-01 01:00:00',
'2017-01-01 02:00:00', '2017-01-01 03:00:00',
'2017-01-01 04:00:00', '2017-01-01 05:00:00',
'2017-01-01 06:00:00', '2017-01-01 07:00:00',
'2017-01-01 08:00:00', '2017-01-01 09:00:00',
'2017-01-01 10:00:00', '2017-01-01 11:00:00',
'2017-01-01 12:00:00', '2017-01-01 13:00:00',
'2017-01-01 14:00:00', '2017-01-01 15:00:00',
'2017-01-01 16:00:00', '2017-01-01 17:00:00',
'2017-01-01 18:00:00', '2017-01-01 19:00:00',
'2017-01-01 20:00:00', '2017-01-01 21:00:00',
'2017-01-01 22:00:00', '2017-01-01 23:00:00',
'2017-01-02 00:00:00'],
dtype='datetime64[ns]', freq='H')
# 從 2017-1-1 開始,以 1s 為間隔,向後推 10 次
In [23]: pd.date_range('2017-1-1',periods=10,freq='s')
Out[23]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-01 00:00:01',
'2017-01-01 00:00:02', '2017-01-01 00:00:03',
'2017-01-01 00:00:04', '2017-01-01 00:00:05',
'2017-01-01 00:00:06', '2017-01-01 00:00:07',
'2017-01-01 00:00:08', '2017-01-01 00:00:09'],
dtype='datetime64[ns]', freq='S')
# 從 2017-1-1 開始,以 1H20min 為間隔,向後推 10 次
In [24]: pd.date_range('1/1/2017', periods=10, freq='1H20min')
Out[24]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-01 01:20:00',
'2017-01-01 02:40:00', '2017-01-01 04:00:00',
'2017-01-01 05:20:00', '2017-01-01 06:40:00',
'2017-01-01 08:00:00', '2017-01-01 09:20:00',
'2017-01-01 10:40:00', '2017-01-01 12:00:00'],
dtype='datetime64[ns]', freq='80T')
除了生成 DatetimeIndex,我們還可以對已有的 DatetimeIndex 進行操作。這些操作包括選擇、切片等。類似於對 Series 的操作。
In [31]: a = pd.date_range('2017-1-1',periods=10,freq='1D1H')
In [32]: a
Out[32]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-02 01:00:00',
'2017-01-03 02:00:00', '2017-01-04 03:00:00',
'2017-01-05 04:00:00', '2017-01-06 05:00:00',
'2017-01-07 06:00:00', '2017-01-08 07:00:00',
'2017-01-09 08:00:00', '2017-01-10 09:00:00'],
dtype='datetime64[ns]', freq='25H')
# 選取索引為 1 的時間戳
In [33]: a[1]
Out[33]: Timestamp('2017-01-02 01:00:00', freq='25H')
# 對索引從 0 到 4 的時間進行切片
In [34]: a[:5]
Out[34]:
DatetimeIndex(['2017-01-01 00:00:00', '2017-01-02 01:00:00',
'2017-01-03 02:00:00', '2017-01-04 03:00:00',
'2017-01-05 04:00:00'],
dtype='datetime64[ns]', freq='25H')
時序資料檢索
DatetimeIndex 之所以稱之為時間戳索引,當然是它的主要用途是作為 Series 或者 DataFrame 的索引。下面,我們就隨機生成一些資料,然後看一看如果對時間序列資料進行操作。
In [1]: import numpy as np
In [2]: import pandas as pd
# 生成時間索引
In [3]: i = pd.date_range('2017-1-1', periods=20, freq='M')
# 生成隨機資料並新增時間作為索引
In [4]: data = pd.Series(np.random.randn(len(i)), index = i)
# 檢視資料
In [5]: data
Out[5]:
2017-01-31 -1.233579
2017-02-28 0.494723
2017-03-31 -2.160592
2017-04-30 0.517173
2017-05-31 -1.984762
2017-06-30 0.655989
2017-07-31 0.919411
2017-08-31 0.114805
2017-09-30 -0.080374
2017-10-31 1.360448
2017-11-30 -0.417094
2017-12-31 0.555434
2018-01-31 1.659271
2018-02-28 -0.514907
2018-03-31 0.330979
2018-04-30 -0.707362
2018-05-31 -0.724524
2018-06-30 0.362518
2018-07-31 0.157280
2018-08-31 -0.724665
Freq: M, dtype: float64
上面就生成了一個以時間為所以的 Series 序列。其實,這就回到了對 Pandas 中 Series 和 DataFrame 型別資料操作的問題。下面演示一些操作:
# 檢索 2017 年的所有資料
In [12]: data['2017']
Out[12]:
2017-01-31 -1.233579
2017-02-28 0.494723
2017-03-31 -2.160592
2017-04-30 0.517173
2017-05-31 -1.984762
2017-06-30 0.655989
2017-07-31 0.919411
2017-08-31 0.114805
2017-09-30 -0.080374
2017-10-31 1.360448
2017-11-30 -0.417094
2017-12-31 0.555434
Freq: M, dtype: float64
# 檢索 2017 年 7 月到 2018 年 3 月之間的所有資料
In [13]: data['2017-07':'2018-03']
Out[13]:
2017-07-31 0.919411
2017-08-31 0.114805
2017-09-30 -0.080374
2017-10-31 1.360448
2017-11-30 -0.417094
2017-12-31 0.555434
2018-01-31 1.659271
2018-02-28 -0.514907
2018-03-31 0.330979
Freq: M, dtype: float64
# 使用 loc 方法檢索 2017 年 1 月的所有資料
In [14]: data.loc['2017-01']
Out[14]:
2017-01-31 -1.233579
Freq: M, dtype: float64
# 使用 truncate 方法檢索 2017-3-1 到 2018-4-2 期間的資料
In [17]: data.truncate(before='2017-3-1',after='2018-4-2')
Out[17]:
2017-03-31 -2.160592
2017-04-30 0.517173
2017-05-31 -1.984762
2017-06-30 0.655989
2017-07-31 0.919411
2017-08-31 0.114805
2017-09-30 -0.080374
2017-10-31 1.360448
2017-11-30 -0.417094
2017-12-31 0.555434
2018-01-31 1.659271
2018-02-28 -0.514907
2018-03-31 0.330979
Freq: M, dtype: float64
時序資料偏移
對於時序資料的處理,肯定不只是查詢和切片這麼簡單。我們這裡可能會用到 Shifting 方法,將時間索引進行整體偏移。
In [1]: import numpy as np
In [2]: import pandas as pd
# 生成時間索引
In [3]: i = pd.date_range('2017-1-1', periods=5, freq='M')
# 生成隨機資料並新增時間作為索引
In [4]: data = pd.Series(np.random.randn(len(i)), index = i)
# 檢視資料
In [5]: data
Out[5]:
2017-01-31 0.830480
2017-02-28 0.348324
2017-03-31 -0.622078
2017-04-30 -1.192675
2017-05-31 0.441947
Freq: M, dtype: float64
# 將索引向前位移 3 個單位,也就是資料向後位移 3 個單位,缺失資料 Pandas 會用 NaN 自動填充
In [8]: data.shift(3)
Out[8]:
2017-01-31 NaN
2017-02-28 NaN
2017-03-31 NaN
2017-04-30 0.830480
2017-05-31 0.348324
Freq: M, dtype: float64
# 將索引向後位移 3 個單位,也就是資料向前位移 3 個單位
In [9]: data.shift(-3)
Out[9]:
2017-01-31 -1.192675
2017-02-28 0.441947
2017-03-31 NaN
2017-04-30 NaN
2017-05-31 NaN
Freq: M, dtype: float64
# 將索引的時間向後移動 3 天
In [10]: data.shift(3,freq='D')
Out[10]:
2017-02-03 0.830480
2017-03-03 0.348324
2017-04-03 -0.622078
2017-05-03 -1.192675
2017-06-03 0.441947
dtype: float64
時序資料重取樣
除了 Shifting 方法,重取樣 Resample 也會經常用到。Resample 可以提升或降低一個時間索引序列的頻率,大有用處。例如:當時間序列資料量非常大時,我們可以通過低頻率取樣的方法得到規模較小到時間覆蓋依然較為全面的新資料集。另外,對於多個不同頻率的資料集需要資料對齊時,重取樣可以十分重要的手段。
In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: i = pd.date_range('2017-1-1', periods=20, freq='D')
In [4]: data = pd.Series(np.random.randn(len(i)), index = i)
In [5]: data
Out[5]:
2017-01-01 0.384984
2017-01-02 0.341555
2017-01-03 -0.100246
2017-01-04 -0.660066
2017-01-05 0.007575
2017-01-06 2.402068
2017-01-07 -0.365657
2017-01-08 -0.853025
2017-01-09 0.588139
2017-01-10 0.047322
2017-01-11 0.213384
2017-01-12 1.056038
2017-01-13 -1.588518
2017-01-14 0.076655
2017-01-15 1.467056
2017-01-16 -1.877541
2017-01-17 0.003218
2017-01-18 -0.811914
2017-01-19 0.143571
2017-01-20 0.837088
Freq: D, dtype: float64
# 按照 2 天進行降取樣,並對 2 天對應的資料求和作為新資料
In [6]: data.resample('2D').sum()
Out[6]:
2017-01-01 0.726539
2017-01-03 -0.760312
2017-01-05 2.409643
2017-01-07 -1.218682
2017-01-09 0.635461
2017-01-11 1.269422
2017-01-13 -1.511864
2017-01-15 -0.410485
2017-01-17 -0.808696
2017-01-19 0.980658
Freq: 2D, dtype: float64
# 按照 2 天進行降取樣,並對 2 天對應的資料求平均值作為新資料
In [7]: data.resample('2D').mean()
Out[7]:
2017-01-01 0.363269
2017-01-03 -0.380156
2017-01-05 1.204821
2017-01-07 -0.609341
2017-01-09 0.317730
2017-01-11 0.634711
2017-01-13 -0.755932
2017-01-15 -0.205243
2017-01-17 -0.404348
2017-01-19 0.490329
Freq: 2D, dtype: float64
# 按照 2 天進行降取樣,並選取對應 2 天的最大值作為新資料
In [9]: data.resample('2D').max()
Out[9]:
2017-01-01 0.384984
2017-01-03 -0.100246
2017-01-05 2.402068
2017-01-07 -0.365657
2017-01-09 0.588139
2017-01-11 1.056038
2017-01-13 0.076655
2017-01-15 1.467056
2017-01-17 0.003218
2017-01-19 0.837088
Freq: 2D, dtype: float64
# 按照 2 天進行降取樣,並將對應 2 天資料的原值、最大值、最小值、以及臨近值列出
In [10]: data.resample('2D').ohlc()
Out[10]:
open high low close
2017-01-01 0.384984 0.384984 0.341555 0.341555
2017-01-03 -0.100246 -0.100246 -0.660066 -0.660066
2017-01-05 0.007575 2.402068 0.007575 2.402068
2017-01-07 -0.365657 -0.365657 -0.853025 -0.853025
2017-01-09 0.588139 0.588139 0.047322 0.047322
2017-01-11 0.213384 1.056038 0.213384 1.056038
2017-01-13 -1.588518 0.076655 -1.588518 0.076655
2017-01-15 1.467056 1.467056 -1.877541 -1.877541
2017-01-17 0.003218 0.003218 -0.811914 -0.811914
2017-01-19 0.143571 0.837088 0.143571 0.837088
取樣操作起來非常簡單,只是需要注意取樣後對新資料不同的處理方法。上面介紹的是降頻取樣。我們也可以升頻取樣。
繼續沿用上面 data 的示例資料
# 時間頻率從天提升到小時,並使用相同的資料對新增加行填充
In [11]: data.resample('H').ffill()
Out[11]:
2017-01-01 00:00:00 0.384984
2017-01-01 01:00:00 0.384984
2017-01-01 02:00:00 0.384984
2017-01-01 03:00:00 0.384984
2017-01-01 04:00:00 0.384984
...
2017-01-19 21:00:00 0.143571
2017-01-19 22:00:00 0.143571
2017-01-19 23:00:00 0.143571
2017-01-20 00:00:00 0.837088
Freq: H, Length: 457, dtype: float64
# 時間頻率從天提升到小時,不對新增加行填充
In [12]: data.resample('H').asfreq()
Out[12]:
2017-01-01 00:00:00 0.384984
2017-01-01 01:00:00 NaN
2017-01-01 02:00:00 NaN
...
2017-01-19 23:00:00 NaN
2017-01-20 00:00:00 0.837088
Freq: H, Length: 457, dtype: float64
# 時間頻率從天提升到小時,只對新增加前 3 行填充
In [13]: data.resample('H').ffill(limit=3)
Out[13]:
2017-01-01 00:00:00 0.384984
2017-01-01 01:00:00 0.384984
2017-01-01 02:00:00 0.384984
2017-01-01 03:00:00 0.384984
2017-01-01 04:00:00 NaN
2017-01-01 05:00:00 NaN
...
2017-01-19 21:00:00 NaN
2017-01-19 22:00:00 NaN
2017-01-19 23:00:00 NaN
2017-01-20 00:00:00 0.837088
Freq: H, Length: 457, dtype: float64
相關文章
- 【時間序列分析】01. 時間序列·平穩序列
- 時間序列分析
- [譯] Python 的時間序列分析:簡介Python
- python 時間序列Python
- 時間序列結構變化分析:Python實現時間序列變化點檢測Python
- 時間序列分析基本思想及時間序列建模步驟
- 時間序列分析(二)--指數平滑
- 用Python語言進行時間序列ARIMA模型分析Python模型
- 時間序列分析(一)--移動平均
- eviews時間序列分析課堂筆記View筆記
- 時間序列分析專題——指數平滑模型模型
- 時間序列知識圖譜-《利用Python進行資料分析》Python
- 人工智慧 (07) 時間序列資料分析人工智慧
- 時間序列分析 | 相似性度量基本方法
- python時間序列缺失值補零Python
- Python Pandas 時間序列雙軸折線圖Python
- 大資料分析筆記 (7) - 時間序列分析(Time Series Analysis)大資料筆記
- 將VAE用於時間序列:生成時間序列的合成資料
- 用R語言進行時間序列ARMA模型分析R語言模型
- Python ArcPy批次拼接長時間序列柵格影像Python
- 會思考的飲水機:基於時間序列分析節能30%+
- [深度學習] 時間序列分析工具TSLiB庫使用指北深度學習
- 用python做時間序列預測一:初識概念Python
- 如何用Python做輿情時間序列視覺化?Python視覺化
- 基於圖論的時間序列資料平穩性與連通性分析:利用圖形、數學和 Python 揭示時間序列資料中的隱藏模式圖論Python模式
- 論文---時間序列----TimeLLM
- 用python做時間序列預測九:ARIMA模型簡介Python模型
- SOFTS: 時間序列預測的最新模型以及Python使用示例模型Python
- 統計學入門:時間序列分析基礎知識詳解
- 時間序列資料的處理
- 論文---時間序列--DLinear
- 時間序列分析專題——利用SPSS專家建模器進行建模SPSS
- 時間管理類APP分析:拇指時間APP
- 用Python預測「週期性時間序列」的正確姿勢Python
- 應用時間序列法預測收入
- 遷移學習時間序列分類遷移學習
- 技術乾貨| MongoDB時間序列集合MongoDB
- [譯] 層次時間序列預測法