(數據科學學習手札99)掌握pandas中的時序數據分組運算

本文示例程式碼及文件已上傳至我的Github倉庫//github.com/CNFeffery/DataScienceStudyNotes

1 簡介

  我們在使用pandas分析處理時間序列數據時,經常需要對原始時間粒度下的數據,按照不同的時間粒度進行分組聚合運算,譬如基於每個交易日的股票收盤價,計算每個月的最低和最高收盤價。

  而在pandas中,針對不同的應用場景,我們可以使用resample()groupby()以及Grouper()來非常高效快捷地完成此類任務。

圖1

2 在pandas中進行時間分組聚合

  在pandas中根據具體任務場景的不同,對時間序列進行分組聚合可通過以下兩類方式實現:

2.1 利用resample()對時序數據進行分組聚合

  resample原始的意思是重取樣,可分為上取樣下取樣,而我們通常情況下使用的都是下取樣,也就是從高頻的數據中按照一定規則計算出更低頻的數據,就像我們一開始說的對每日數據按月匯總那樣。

  如果你熟悉pandas中的groupby()分組運算,那麼你就可以很快地理解resample()的使用方式,它本質上就是在對時間序列數據進行「分組」,最基礎的參數為rule,用於設置按照何種方式進行重取樣,就像下面的例子那樣:

import pandas as pd

# 記錄了2013-02-08到2018-02-07之間每個交易日蘋果公司的股價
AAPL = pd.read_csv('AAPL.csv', parse_dates=['date'])

# 以月為統計窗口計算每月股票最高收盤價
(
    AAPL
    .set_index('date') # 設置date為index
    .resample('M') # 以月為單位
    .agg({
        'close': ['max', 'min']
    })
)

圖2

  可以看到,在上面的例子中,我們對index為日期時間類型的DataFrame應用resample()方法,傳入的參數'M'resample第一個位置上的參數rule,用於確定時間窗口的規則,譬如這裡的字元串'M'就代表月且聚合結果中顯示對應月的最後一天,常用的固化的時間窗口規則如下表所示:

規則 說明
W 星期
M 月,顯示為當月最後一天
MS 月,顯示為當月第一天
Q 季度,顯示為當季最後一天
QS 季度,顯示為當季第一天
A 年,顯示為當年最後一天
AS 年,顯示為當年第一天
D
H 小時T
T或min 分鐘
S
L或 ms 毫秒

  且這些規則都可以在前面添加數字實現倍數效果:

# 以6個月為統計窗口計算每月股票平均收盤價且顯示為當月第一天
(
    AAPL
    .set_index('date') # 設置date為index
    .resample('6MS') # 以6個月為單位
    .agg({
        'close': 'mean'
    })
)

圖3

  且resample()非常貼心之處在於它會自動幫你對齊到規整的時間單位上,譬如我們這裡只有交易日才會有記錄,如果我們設置的時間單位下無對應記錄,也會為你保留帶有缺失值記錄的時間點:

(
    AAPL
    .set_index('date') # 設置date為index
    .resample('1D') # 以1日為單位
    .agg({
        'close': 'mean'
    })
)

圖4

  而通過參數closed我們可以為細粒度的時間單位設置區間閉合方式,譬如我們以2日為單位,將closed設置為'right'時,從第一行記錄開始計算所落入的時間窗口時,其對應為時間窗口的右邊界,從而影響後續所有時間單元的劃分方式:

(
    AAPL
    .set_index('date') # 設置date為index
    .resample('2D', closed='right')
    .agg({
        'close': 'mean'
    })
)

圖5

  而即使你的數據框index不是日期時間類型,也可以使用參數on來傳入日期時間列名實現同樣的效果。

2.2 利用groupby()+Grouper()實現混合分組

  有些情況下,我們不僅僅需要利用時間類型列來分組,也可能需要包含時間類型在內的多個列共同進行分組,這種情況下我們就可以使用到Grouper()

  它通過參數freq傳入等價於resample()rule的參數,並利用參數key指定對應的時間類型列名稱,但是可以幫助我們創建分組規則後傳入groupby()中:

# 分別對蘋果與微軟每月平均收盤價進行統計
(
    pd
    .read_csv('AAPL&MSFT.csv', parse_dates=['date'])
    .groupby(['Name', pd.Grouper(freq='MS', key='date')])
    .agg({
        'close': 'mean'
    })
)

圖6

  且在此種混合分組模式下,我們可以非常方便的配合applytransform等操作,這裡就不再贅述。


  以上就是本文的全部內容,歡迎在評論區與我進行討論~