數(shù)據(jù)分析經(jīng)常會(huì)遇到帶有時(shí)間序列的數(shù)據(jù)阅悍,接下來(lái)我們看一下悼嫉,利用pandas如何處理這類(lèi)數(shù)據(jù)解孙。
時(shí)間序列
- 時(shí)間戳(timestamp)
- 固定周期(period)
- 時(shí)間間隔(interval)
一、創(chuàng)建時(shí)間序列
1双戳、date_range
- 可以指定開(kāi)始時(shí)間與周期
- H:小時(shí)
- D:天
- M:月
以天(day)為單位虹蒋,輸出后10天的時(shí)間序列
#TIMES #2016 Jul 1 7/1/2016 1/7/2016 2016-07-01 2016/07/01
#時(shí)間格式可以換成上面的
rng = pd.date_range('2016/07/01',periods=10,freq='D')
rng
也可以3天為單位,輸出后10個(gè)序列
rng = pd.date_range('2016/07/01',periods=10,freq='3D')
rng
或者指定起始時(shí)間
rng = pd.date_range(start = '2016/07/01',end = '2016/07/10',freq='D')
rng
生成Series序列
time = pd.Series(np.random.randn(20),index=pd.date_range(dt.datetime(2016,1,1),periods=20))
time
2飒货、truncate過(guò)濾
time.truncate(before='2016-1-10')#過(guò)濾掉2016-1-10之前的數(shù)據(jù)
time.truncate(after='2016-1-10')#過(guò)濾掉之后的
提取數(shù)據(jù)
print(time['2016-01-15'])
print(time['2016-01-15':'2016-01-20'])#切片的方式
data = pd.date_range('2010-01-01','2011-01-01',freq='M')
data
參數(shù)freq中可以選的數(shù)值:
3魄衅、時(shí)間戳
pd.Timestamp('2016-07-10')
#可以指定更多細(xì)節(jié)
pd.Timestamp('2016-07-10 10')
pd.Timestamp('2016-07-10 10:15')
4、時(shí)間區(qū)間
pd.Period('2016-01')
pd.Period('2016-01-01')
5塘辅、時(shí)間加減
- TIME OFFSETS
產(chǎn)生一個(gè)一天的時(shí)間偏移量
#產(chǎn)生一個(gè)一天的時(shí)間偏移量
pd.Timedelta('1 day')
#得到2016-01-01 10:10的后一天時(shí)刻:
pd.Period('2016-01-01 10:10') + pd.Timedelta('1 day')
#時(shí)間戳加減:
pd.Timestamp('2016-01-01 10:10') + pd.Timedelta('1 day')
#加15ns
pd.Timestamp('2016-01-01 10:10') + pd.Timedelta('15 ns')
在時(shí)間間隔freq參數(shù)中徐绑,我們既可以寫(xiě)成25H,也可以寫(xiě)成1D1H這種通俗的表達(dá):
pd.period_range('2016-01-01 10:10',freq='25H',periods=10)
pd.period_range('2016-01-01 10:10',freq='1D1H',periods=10)
6莫辨、指定索引
rng = pd.date_range('2016 Jul 1',periods=10,freq='D')
pd.Series(range(len(rng)),index=rng)
#構(gòu)造任意的Series結(jié)構(gòu)時(shí)間序列數(shù)據(jù):
periods=[pd.Period('2016-01'),pd.Period('2016-02'),pd.Period('2016-03')]
ts = pd.Series(np.random.randn(len(periods)),index=periods)
ts
type(ts.index)
7傲茄、時(shí)間戳和時(shí)間周期可以轉(zhuǎn)換
#產(chǎn)生時(shí)間周期
ts = pd.Series(range(10),pd.date_range('07-10-16 8:00',periods=10,freq='H'))
ts
#將時(shí)間周期轉(zhuǎn)化為時(shí)間戳
ts_period = ts.to_period()
ts_period
8、時(shí)間周期和時(shí)間戳的區(qū)別
- 對(duì)時(shí)間周期的切片操作
ts_period['2016-07-10 08:30':'2016-07-10 11:45']
- 對(duì)時(shí)間戳的切片操作
ts['2016-07-10 08:30':'2016-07-10 11:45']
二沮榜、數(shù)據(jù)重采樣
- 時(shí)間數(shù)據(jù)由一個(gè)頻率轉(zhuǎn)換到另一個(gè)頻率
- 降采樣:例如將365天數(shù)據(jù)變?yōu)?2個(gè)月的數(shù)據(jù)
- 升采樣:相反
#從1/1/2011開(kāi)始盘榨,時(shí)間間隔為1天,產(chǎn)生90個(gè)時(shí)間數(shù)據(jù)
rng = pd.date_range('1/1/2011',periods=90,freq='D')
ts = pd.Series(np.random.randn(len(rng)),index=rng)
ts.head()
1蟆融、降采樣
#將以上數(shù)據(jù)降采樣為月數(shù)據(jù)草巡,觀察每個(gè)月數(shù)據(jù)之和、
ts.resample('M').sum()
#降采樣為3天型酥,并求和
ts.resample('3D').sum()
計(jì)算降采樣后數(shù)據(jù)均值
#計(jì)算降采樣后數(shù)據(jù)均值
day3Ts=ts.resample('3D').mean()
day3Ts
2山憨、升采樣
直接升采樣是有問(wèn)題的,因?yàn)橛袛?shù)據(jù)缺失
#
day3Ts.resample('D').asfreq()
使用插值的方法
- ffill 空值取前面的值
- bfill 空值取后面的值
- interpolate 線(xiàn)性取值
day3Ts.resample('D').ffill(1)#一個(gè)值填充
day3Ts.resample('D').ffill(2)#兩個(gè)值填充
全部空值填充
day3Ts.resample('D').ffill()
day3Ts.resample('D').bfill(1)
day3Ts.resample('D').bfill(2)
day3Ts.resample('D').bfill()
使用interpolate線(xiàn)性取值
# 使用interpolate線(xiàn)性取值
day3Ts.resample('D').interpolate('linear')
三弥喉、Pandas滑動(dòng)窗口
為了提升數(shù)據(jù)的準(zhǔn)確性郁竟,將某個(gè)點(diǎn)的取值擴(kuò)大到包含這個(gè)點(diǎn)的一段區(qū)間,用區(qū)間來(lái)進(jìn)行判斷由境,這個(gè)區(qū)間就是窗口棚亩。例如想使用2011年1月1日的一個(gè)數(shù)據(jù)蓖议,單取這個(gè)時(shí)間點(diǎn)的數(shù)據(jù)當(dāng)然是可行的,但是太過(guò)絕對(duì)讥蟆,有沒(méi)有更好的辦法呢勒虾?可以選取2010年12月16日到2011年1月15日,通過(guò)求均值來(lái)評(píng)估1月1日這個(gè)點(diǎn)的值瘸彤,2010-12-16到2011-1-15就是一個(gè)窗口修然,窗口的長(zhǎng)度window=30.
移動(dòng)窗口就是窗口向一端滑行,默認(rèn)是從右往左质况,每次滑行并不是區(qū)間整塊的滑行低零,而是一個(gè)單位一個(gè)單位的滑行。例如窗口2010-12-16到2011-1-15拯杠,下一個(gè)窗口并不是2011-1-15到2011-2-15,而是2010-12-17到2011-1-16(假設(shè)數(shù)據(jù)的截取是以天為單位)啃奴,整體向右移動(dòng)一個(gè)單位潭陪,而不是一個(gè)窗口。這樣統(tǒng)計(jì)的每個(gè)值始終都是30單位的均值最蕾。
也就是我們?cè)诮y(tǒng)計(jì)學(xué)中的移動(dòng)平均法依溯。
import matplotlib.pylab
import numpy as np
import pandas as pd
%matplotlib inline
df = pd.Series(np.random.randn(600),index=pd.date_range('7/1/2016',freq='D',periods=600))
df.head()
#指定該序列一個(gè)單位長(zhǎng)度為10的滑塊
r=df.rolling(window = 10)
r
#輸出滑塊內(nèi)的平均值,窗口中的值從覆蓋整個(gè)窗口的位置開(kāi)始產(chǎn)生瘟则,在此之前即為NaN,舉例如下:窗口大小為10黎炉,前9個(gè)都不足夠?yàn)橐粋€(gè)一個(gè)窗口的長(zhǎng)度,因此都無(wú)法取值醋拧。
r.mean()
# 通過(guò)畫(huà)圖庫(kù)來(lái)看原始序列與滑動(dòng)窗口產(chǎn)生序列的關(guān)系圖慷嗜,原始數(shù)據(jù)用紅色表示,移動(dòng)平均后數(shù)據(jù)用藍(lán)色點(diǎn)表示:
import matplotlib.pyplot as plt
plt.figure(figsize=(15,5))
df.plot(style='r--')
df.rolling(window=10).mean().plot(style='b')#可以看到丹壕,原始值浮動(dòng)差異較大庆械,而移動(dòng)平均后數(shù)值較為平穩(wěn)。