這節依然是時間相關的知識, 前面是側重於時間點的一些方法, 這節要介紹的是關於時間段的相關知識.
建立一個 period 物件:
import pandas as pd
y = pd.Period('2016')
y
輸出:
Period('2016', 'A-DEC')
A 代表 Annual | 年度的
DEC 代表 December | 12月
整體表示已經建立了一個 2016年的時間段物件, 並賦值給變數 y, 現在就可以呼叫這個物件的方法:
求2016年的起始時間:
y.start_time
輸出:
Timestamp('2016-01-01 00:00:00')
2016年的結束時間:
y.end_time
輸出:
Timestamp('2016-12-31 23:59:59.999999999')
建立 2019年1月的時間段物件, 注意, 這裡具體到月份了:
m = pd.Period('2019-01')
m
輸出:
Period('2019-01', 'M')
求 2019年1月的起始時間:
m.start_time
輸出:
Timestamp('2019-01-01 00:00:00')
2019年1月的結束時間:
m.end_time
輸出:
Timestamp('2019-01-31 23:59:59.999999999')
還可以對月份做加減操作:
m + 1
輸出:
Period('2019-02', 'M')
從2019年1月往後推12個月:
m + 12
輸出:
Period('2020-01', 'M')
從輸出可以看出 Pandas 對日曆的精準掌握.
建立以天為單位的時間段物件:
d = pd.Period('2019-2-12')
d
輸出:
Period('2019-02-12', 'D')
檢視起始時間:
d.start_time
輸出:
Timestamp('2019-02-12 00:00:00')
檢視結束時間:
d.end_time
輸出:
Timestamp('2019-02-12 23:59:59.999999999')
對天進行加運算:
d + 3
輸出:
Period('2019-02-15', 'D')
建立以小時為單位的時間段物件:
h = pd.Period('2019-2-12 23')
h
輸出:
Period('2019-02-12 23:00', 'H')
這裡插播一條意外, 如果我按照如下格式寫時間:
h = pd.Period('2019-2-12 23:09:7')
h
得到的就是以秒為單位的時間段物件:
Period('2019-02-12 23:09:07', 'S')
那麼如果我固執地還想要以小時為單位的時間段物件呢? 那麼就可以用引數 freq 的值加以限制:
h = pd.Period('2019-2-12 23:09:7', freq='H')
h
這樣就得到了以小時為單位的時間段物件:
Period('2019-02-12 23:00', 'H')
同樣可以進行加減運算:
h+3
輸出:
Period('2019-02-13 02:00', 'H')
也可以用這種方式推移時間, 得到效果跟加運算是一樣的:
h+pd.offsets.Hour(3)
輸出:
Period('2019-02-13 02:00', 'H')
我們在做資料分析的時候還經常遇到以季度為時間節點的分析需求, 我們可以這樣建立以季度為單位的時間段物件:
q = pd.Period('2019Q1')
q
輸出:
Period('2019Q1', 'Q-DEC')
同樣可以進行加減運算:
q+1
輸出:
Period('2019Q2', 'Q-DEC')
檢視起始時間:
q.start_time
輸出:
Timestamp('2019-01-01 00:00:00')
檢視結束時間:
q.end_time
輸出:
Timestamp('2019-03-31 23:59:59.999999999')
透過上面的方式檢視的起始時間和結束時間都是精確到秒的, 但是從實際的角度出發, 通常我們如果需要按季度做一些分析, 應該只要精確到月就可以了, 可以透過如下方式做轉換:
q.asfreq('M', how='start')
輸出:
Period('2019-01', 'M')
以及精確到月的結束時間:
q.asfreq('M', how='end')
輸出:
Period('2019-03', 'M')
以季度為單位建立時間段物件:
idx = pd.period_range('2011', '2018', freq='Q')
idx
輸出:
PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
'2012Q3', '2012Q4', '2013Q1', '2013Q2', '2013Q3', '2013Q4',
'2014Q1', '2014Q2', '2014Q3', '2014Q4', '2015Q1', '2015Q2',
'2015Q3', '2015Q4', '2016Q1', '2016Q2', '2016Q3', '2016Q4',
'2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'],
dtype='period[Q-DEC]', freq='Q-DEC')
這樣活得的就是一個 list, 其中的每個元素都是一個 period 物件, 因此都可以呼叫我們之前所講到的方法, 比如起始時間:
idx[0].start_time
輸出:
Timestamp('2011-01-01 00:00:00')
以及結束時間:
idx[0].end_time
輸出:
Timestamp('2011-03-31 23:59:59.999999999')
period_range() 函式還可以透過如下方式傳參, 以設定取值範圍:
idx = pd.period_range('2011', periods=10, freq='Q')
idx
輸出:
PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
'2012Q3', '2012Q4', '2013Q1', '2013Q2'],
dtype='period[Q-DEC]', freq='Q-DEC')
繼續, 看下面這個例子:
import numpy as np
ps = pd.Series(np.random.randn(len(idx)), idx)
ps
結構稍顯複雜, 解釋一下, 首先利用 numpy 的 random.randn()函式生成一些隨機浮點數, 在這裡是傳入了 idx 的長度作為引數, 所以就會生成 10個隨機的浮點數, 並且是以陣列的形式返回. 然後是用 Pandas 的 Series()函式給這個陣列加上索引, (按照我前面講過的方法, 按下 shift+tab 就可以檢視任意函式的用法, 這裡 Series() 函式的第一個引數剛好是陣列, 第二個引數就是索引), 索引的值, 就是我們上面生成的 period 物件:
2011Q1 -0.108024
2011Q2 -0.535832
2011Q3 1.258304
2011Q4 -0.490206
2012Q1 -1.517975
2012Q2 0.329804
2012Q3 -0.017833
2012Q4 -1.739612
2013Q1 -0.349370
2013Q2 0.341614
Freq: Q-DEC, dtype: float64
檢視陣列的索引:
ps.index
輸出:
PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
'2012Q3', '2012Q4', '2013Q1', '2013Q2'],
dtype='period[Q-DEC]', freq='Q-DEC')
按年份檢視資料:
ps['2011']
輸出:
2011Q1 -0.108024
2011Q2 -0.535832
2011Q3 1.258304
2011Q4 -0.490206
Freq: Q-DEC, dtype: float64
跨年檢視資料:
ps['2011':'2013']
輸出:
2011Q1 -0.108024
2011Q2 -0.535832
2011Q3 1.258304
2011Q4 -0.490206
2012Q1 -1.517975
2012Q2 0.329804
2012Q3 -0.017833
2012Q4 -1.739612
2013Q1 -0.349370
2013Q2 0.341614
Freq: Q-DEC, dtype: float64
如果覺得 Q1, Q2 這種形式不符合人的閱讀習慣, 還可以將其轉為正常的日期格式:
pst = ps.to_timestamp()
pst
輸出:
2011-01-01 -0.108024
2011-04-01 -0.535832
2011-07-01 1.258304
2011-10-01 -0.490206
2012-01-01 -1.517975
2012-04-01 0.329804
2012-07-01 -0.017833
2012-10-01 -1.739612
2013-01-01 -0.349370
2013-04-01 0.341614
Freq: QS-OCT, dtype: float64
再開檢視一下改變後的索引:
pst.index
輸出:
DatetimeIndex(['2011-01-01', '2011-04-01', '2011-07-01', '2011-10-01',
'2012-01-01', '2012-04-01', '2012-07-01', '2012-10-01',
'2013-01-01', '2013-04-01'],
dtype='datetime64[ns]', freq='QS-OCT')
當然, 還可以再轉回去:
pst.to_period()
輸出:
2011Q1 -0.108024
2011Q2 -0.535832
2011Q3 1.258304
2011Q4 -0.490206
2012Q1 -1.517975
2012Q2 0.329804
2012Q3 -0.017833
2012Q4 -1.739612
2013Q1 -0.349370
2013Q2 0.341614
Freq: Q-DEC, dtype: float64
再來舉一個現實的例子, 請看下圖, 上面是我們從 csv 檔案直接導過來的資料格式, 但是我們希望轉換成下面的格式, 首先是讓季度時間段作為索引列, 並且加上每個季度的起始時間和結束時間:
首先我把 csv 檔案的截圖放在這裡, 大家需要手動敲一下:
引入檔案:
import pandas as pd
df = pd.read_csv('/Users/rachel/Sites/pandas/py/pandas/18_ts_period/wmt.csv')
df
輸出:
設定索引列:
df.set_index('Line Item', inplace=True)
df
輸出:
轉換索引列:
df = df.T
df
輸出:
獲取這個資料表的索引 list:
df.index
輸出:
Index(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'], dtype='object')
利用 Pandas 的 PeriodIndex()函式, 索引 list 的資料格式改為 period 物件的 list:
df.index = pd.PeriodIndex(df.index, freq = 'Q')
df.index
輸出:
PeriodIndex(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'], dtype='period[Q-DEC]', freq='Q-DEC')
轉換為 period 物件就是為了可以呼叫 start_time()和 end_time()函式.
接下來就是為 df 增加兩個欄位:
df['start time'] = df.index.map(lambda x: x.start_time)
df
輸出:
df['end time'] = df.index.map(lambda x: x.end_time)
df
輸出:
以上, 就是這一節的全部內容, 方法零零碎碎的看著有點多, 我覺得也不用一下都記到吧, 主要就是先照著敲一遍, 大概有個印象.
本作品採用《CC 協議》,轉載必須註明作者和本文連結