pandas資料分析基礎之時間序列
目錄
- 一、時間序列是什麼
- 二、時間序列的選取-時間字串/at_time/between_time/asof
- 三、時間序列的生成-datetime/date_range(start,end,perios,freq)
- 四、時間序列的偏移量對照表-freq
- 五、時間序列的前移或後移-shift/通過Day或MonthEnd
- 五、時區處理-tz/tz_convert
- 六、時期及算術運算-period
- 七、頻率轉換-resample
一、時間序列是什麼
時間序列在多個時間點觀察或測量到的任何事物,很多都是固定頻率出現 的,比如每15秒、每5分鐘、每月。
padnas提供了一組標準的時間序列處理工具和資料演算法,基本的時間序列型別是以時間戳為索引的Series。
當建立一個帶有DatetimeIndex的Series時,pandas就會知道物件是一個時間序列,用Numpy的datetime64資料以納秒形式儲存時間。
dates=[ datetime(2020,1,2),datetime(2020,1,5),datetime(2020,1,7), datetime(2020,1,8),datetime(2020,1,10),datetime(2020,1,12) ] ts=pd.Series(np.random.randn(6),index=dates) ts 2020-01-02 -0.140776 2020-01-05 0.185088 2020-01-07 0.555777 2020-01-08 0.693348 2020-01-10 -0.213715 2020-01-12 -0.259721 dtype: float64 ts.index DatetimeIndex(['2020-01-02', '2020-01-05', '2020-01-07', '2020-01-08', '2020-01-10', '2020-01-12'], dtype='datetime64[ns]', freq=None) ts.index.dtype dtype('<M8[ns]')
二、時間序列的選取-時間字串/at_time/between_time/asof
1.傳入一個可以被解釋為日期的字串
ts['1/10/2020'] -0.3216128833894315 ts['2020-01-02'] 0.47508960825683716 #也可以只傳入年或月 longer_ts['2021'] 2021-01-01 1.596179 2021-01-02 -0.458160 2021-01-03 1.380482 ... 2021-12-29 0.343524 2021-12-30 0.040584 2021-12-31 -1.616620 Freq: D, Length: 365, dtype: float64 #通過日期進行切片 ts[datetime(2020,1,7):] 2020-01-07 0.555777 2020-01-08 0.693348 2020-01-10 -0.213715 2020-01-12 -0.259721 dtype: float64 ts['1/6/2020':'1/11/2020'] 2020-01-07 0.555777 2020-01-08 0.693348 2020-01-10 -0.213715 dtype: float64
2.通過at_time獲取指定時間點
# 生成一個交易日內的日期範圍和時間序列,以分為緯度
rng=pd.date_range('2020-06-01 09:30','2020-06-01 15:59',freq='T')
#生成5天的時間點
rng=rng.append([rng+pd.offsets.BDay(i) for i in range(1,4)])
ts=pd.Series(np.arange(len(rng),dtype=float),index=rng)
#抽取指定時間點:10點0分的資料
ts.at_time(time(10,0))
3.通過between_time獲取兩個時間點之間的資料
ts.between_time(time(10,0),time(10,1))
4.通過asof獲取最接近當前時間的資料
asof解釋:最後一行不是NaN值的值。通俗的說:假如我有一組資料,某個點的時候這個值是NaN,那就求這個值之前最近一個不是NaN的值是多少
selection=pd.date_range('2020-06-01 10:00',periods=4,freq='B')
ts.asof(selection)
三、時間序列的生成-datetime/date_range(start,end,perios,freq)
1.直接使用date_time生成
dates=[
datetime(2020,1,2),datetime(2020,1,5),datetime(2020,1,7),
datetime(2020,1,8),datetime(2020,1,10),datetime(2020,1,12)
]
ts=pd.Series(np.random.randn(6),index=dates)
date_range可以生成指定長度的DatetimeIndex
- 指定開始和結束
pd.date_range('4/1/2020','6/1/2020')
DatetimeIndex(['2020-04-01', '2020-04-02', '2020-04-03', '2020-04-04',
'2020-04-05', '2020-04-06', '2020-04-07', '2020-04-08',
'2020-04-09', '2020-04-10', '2020-04-11', '2020-04-12',
'2020-04-13', '2020-04-14', '2020-04-15', '2020-04-16',
'2020-04-17', '2020-04-18', '2020-04-19', '2020-04-20',
'2020-04-21', '2020-04-22', '2020-04-23', '2020-04-24',
'2020-04-25', '2020-04-26', '2020-04-27', '2020-04-28',
'2020-04-29', '2020-04-30', '2020-05-01', '2020-05-02',
'2020-05-03', '2020-05-04', '2020-05-05', '2020-05-06',
'2020-05-07', '2020-05-08', '2020-05-09', '2020-05-10',
'2020-05-11', '2020-05-12', '2020-05-13', '2020-05-14',
'2020-05-15', '2020-05-16', '2020-05-17', '2020-05-18',
'2020-05-19', '2020-05-20', '2020-05-21', '2020-05-22',
'2020-05-23', '2020-05-24', '2020-05-25', '2020-05-26',
'2020-05-27', '2020-05-28', '2020-05-29', '2020-05-30',
'2020-05-31', '2020-06-01'],
dtype='datetime64[ns]', freq='D')
- 指定步長
pd.date_range(start='4/1/2020',periods=20)
DatetimeIndex(['2020-04-01', '2020-04-02', '2020-04-03', '2020-04-04',
'2020-04-05', '2020-04-06', '2020-04-07', '2020-04-08',
'2020-04-09', '2020-04-10', '2020-04-11', '2020-04-12',
'2020-04-13', '2020-04-14', '2020-04-15', '2020-04-16',
'2020-04-17', '2020-04-18', '2020-04-19', '2020-04-20'],
dtype='datetime64[ns]', freq='D')
- 指定偏移量
M:日曆月末最後一天
pd.date_range('1/1/2020','12/1/2020',freq='M')
DatetimeIndex(['2020-01-31', '2020-02-29', '2020-03-31', '2020-04-30',
'2020-05-31', '2020-06-30', '2020-07-31', '2020-08-31',
'2020-09-30', '2020-10-31', '2020-11-30'],
dtype='datetime64[ns]', freq='M')
BM:每月的最後個工作日,business end of month
pd.date_range('1/1/2020','12/1/2020',freq='BM')
DatetimeIndex(['2020-01-31', '2020-02-28', '2020-03-31', '2020-04-30',
'2020-05-29', '2020-06-30', '2020-07-31', '2020-08-31',
'2020-09-30', '2020-10-30', '2020-11-30'],
dtype='datetime64[ns]', freq='BM')
自定義時間偏移,如h、4h、1h30min
pd.date_range('1/1/2020',periods=10,freq='1h30min')
DatetimeIndex(['2020-01-01 00:00:00', '2020-01-01 01:30:00',
'2020-01-01 03:00:00', '2020-01-01 04:30:00',
'2020-01-01 06:00:00', '2020-01-01 07:30:00',
'2020-01-01 09:00:00', '2020-01-01 10:30:00',
'2020-01-01 12:00:00', '2020-01-01 13:30:00'],
dtype='datetime64[ns]', freq='90T')
四、時間序列的偏移量對照表-freq
名稱 | 偏移量型別 | 說明 |
---|---|---|
D | Day | 每日 |
B | BusinessDay | 每工作日 |
H | Hour | 每小時 |
T或min | Minute | 每分 |
S | Second | 每秒 |
L或ms | Milli | 每毫秒 |
U | Micro | 每微秒 |
M | MounthEnd | 每月最後一個日曆日 |
BM | BusinessMonthEnd | 每月最後一個工作日 |
MS | MonthBegin | 每月每一個工作日 |
BMS | BusinessMonthBegin | 每月第一個工作日 |
W-MON、W-TUE... | Week | 指定星期幾(MON、TUE、WED、THU、FRI、SAT、SUM) |
WOM-1MON、WMON-2MON | WeekOfMonth | 產生每月第一、第二、第三或第四周的星期幾 |
Q-JAN、Q-FEB... | QuaterEnd | 對於以指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC)結束的年度,每季度最後一月的最後一個日曆日 |
BQ-JAN、BQ-FEB... | BusinessQuaterEnd | 對於以指定月份結束的年度,每季度最後一月的最後一個工作日 |
QS-JAN、QS-FEB... | QuaterBegin | 對於以指定月份結束的年度,每季度最後一月的第一個日曆日 |
QS-JAN、QS-FEB... | BusinessQuaterBegin | 對於指定月份結束的年度,每季度最後一月的第一個工作日 |
A-JAN、A-FEB... | YearEnd | 每年指定月份的最後一個日曆日 |
BA-JAN、BA-FEB | BusinessYearEnd | 每年指定月份的最後一個日曆日 |
AS-JAN、AS-FEB | YearBegin | 每年指定月份的第一個日曆日 |
BAS-JAN、BAS-FEB | BusinessYearBegin | 每年指定月份的第一個工作日 |
例如,每月第3個星期五
pd.date_range('1/1/2020','9/1/2020',freq='WOM-3FRI')
DatetimeIndex(['2020-01-17', '2020-02-21', '2020-03-20', '2020-04-17',
'2020-05-15', '2020-06-19', '2020-07-17', '2020-08-21'],
dtype='datetime64[ns]', freq='WOM-3FRI')
五、時間序列的前移或後移-shift/通過Day或MonthEnd
shift方法用於執行單純的前移或後移操作
ts=pd.Series(np.random.randn(4),
index=pd.date_range('1/1/2020',periods=4,freq='M'))
ts
2020-01-31 0.185458
2020-02-29 0.549704
2020-03-31 0.146584
2020-04-30 0.983613
Freq: M, dtype: float64
向後移動一個月
ts.shift(1,freq='M')
2020-02-29 0.185458
2020-03-31 0.549704
2020-04-30 0.146584
2020-05-31 0.983613
Freq: M, dtype: float64
向前移動3天
ts.shift(-3,freq='D')
2020-01-28 0.185458
2020-02-26 0.549704
2020-03-28 0.146584
2020-04-27 0.983613
dtype: float64
通過Day或MonthEnd移動
from pandas.tseries.offsets import Day,MonthEnd
now=datetime(2020,1,27)
now+3*Day()
Timestamp('2020-01-30 00:00:00')
now+MonthEnd()
Timestamp('2020-01-31 00:00:00')
五、時區處理-tz/tz_convert
python的時區資訊來自第三方庫pytz,pandas包裝了pytz的功能
檢視所有時區
pytz.common_timezones
轉換時區- tz_convert
rng=pd.date_range('3/9/2020 9:30',periods=6,freq='D',tz='UTC')
ts=pd.Series(np.random.randn(len(rng)),index=rng)
ts
2020-03-09 09:30:00+00:00 -1.779006
2020-03-10 09:30:00+00:00 -0.293860
2020-03-11 09:30:00+00:00 -0.174114
2020-03-12 09:30:00+00:00 0.749316
2020-03-13 09:30:00+00:00 0.342134
2020-03-14 09:30:00+00:00 1.101283
Freq: D, dtype: float64
ts.tz_convert('Asia/Shanghai')
2020-03-09 17:30:00+08:00 -1.779006
2020-03-10 17:30:00+08:00 -0.293860
2020-03-11 17:30:00+08:00 -0.174114
2020-03-12 17:30:00+08:00 0.749316
2020-03-13 17:30:00+08:00 0.342134
2020-03-14 17:30:00+08:00 1.101283
Freq: D, dtype: float64
六、時期及算術運算-period
時期(period)表示的是時間區間,比如數日、數月、數季、數年等
下面這個Period物件表示從2020年1月1日到2020年12月31日之間的整段時間
p=pd.Period(2020,freq='A-DEC')
p
Period('2020', 'A-DEC')
建立規則的時期範圍
#季度為Q生成13個時間
pd.period_range("2019-01", periods=13, freq="Q")
#Q代表季度為頻率,預設的字尾為DEC代表一年以第1個月為結束【最後一個月為1月份】
pd.period_range("2019-01", periods=13, freq="Q-JAN")
# 以季度Q【年為頻率】生成13個時間
pd.period_range("2019-01", periods=13, freq="Y")
#以季度Q【2個月為頻率】生成13個時間
pd.period_range("2019-01", periods=13, freq="2m")
PeriodIndex類儲存了一組Period,可以在pandas資料結構中用作軸索引
rng=pd.period_range('1/1/2020','6/30/2020',freq='M')
rng
PeriodIndex(['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06'], dtype='period[M]', freq='M')
pd.Series(np.random.randn(6),rng)
2020-01 -1.050150
2020-02 -0.828435
2020-03 1.648335
2020-04 1.476485
2020-05 0.779732
2020-06 -1.394688
Freq: M, dtype: float64
使用字串建立PeriodIndex
Q代表季度為頻率,預設的字尾為DEC代表一年以第12個月為結束
pd.PeriodIndex(['2020Q3','2020Q2','2020Q1'],freq='Q-DEC')
Period和PeriodIndex互轉-asfreq
p=pd.Period('2020',freq='A-DEC')
p.asfreq('M',how='start')
Period('2020-01', 'M')
p=pd.Period('2020-08',freq='M')
p.asfreq('A-JUN')
Period('2021', 'A-JUN')
to_period可以將datetime轉period
rng=pd.date_range('1/1/2020',periods=6,freq='D')
ts=pd.Series(np.random.randn(6),index=rng)
ts
2020-01-01 -1.536552
2020-01-02 -0.550879
2020-01-03 0.601546
2020-01-04 -0.103521
2020-01-05 0.445024
2020-01-06 1.127598
Freq: D, dtype: float64
ts.to_period('M')
2020-01 -1.536552
2020-01 -0.550879
2020-01 0.601546
2020-01 -0.103521
2020-01 0.445024
2020-01 1.127598
Freq: M, dtype: float64
to_timespame可以將Period轉換為時間戳
ts.to_period('M').to_timestamp()
七、頻率轉換-resample
重取樣(resampling)指將時間序列從一個頻率轉換到另一個頻率的處理過程
pandas物件都帶有一個resample方法,是各種頻率轉換的函式
降取樣率
#檢視100天的取樣
rng=pd.date_range('1/1/2020',periods=100,freq='D')
ts=pd.Series(np.random.randn(len(rng)),index=rng)
# 轉為一月的
ts.resample('M').mean()
2020-01-31 -0.049213
2020-02-29 -0.155195
2020-03-31 -0.000091
2020-04-30 -0.023561
Freq: M, dtype: float64
分鐘的取樣轉為5分鐘的
rng=pd.date_range('1/1/2020',periods=12,freq='T')
ts=pd.Series(np.random.randn(len(rng)),index=rng)
ts.resample('5min').sum()
2020-01-01 00:00:00 1.376219
2020-01-01 00:05:00 0.883248
2020-01-01 00:10:00 -0.939534
Freq: 5T, dtype: float64
通過groupby進行取樣,傳入一個能夠訪問時間序列的索引上欄位的函式
rng=pd.date_range('1/1/2020',periods=100,freq='D')
ts=pd.Series(np.random.randn(len(rng)),index=rng)
ts.groupby(lambda x:x.month).mean()
2020-01-31 0.182420
2020-02-29 0.200134
2020-03-31 -0.108818
2020-04-30 -0.187426
Freq: M, dtype: float64
升取樣率
示例: 週數據轉為日
# 週數據
frame=pd.DataFrame(
np.random.randn(2,4),
index=pd.date_range('1/1/2020',periods=2,freq='W-WED'),
columns=['Colorado','Texa','New York','Ohio']
)
# #轉為日
frame.resample('D').asfreq()
#用前面的值填充
frame.resample('D').ffill()
#用後面的值填充
frame.resample('D').bfill()