第十章 時(shí)序數(shù)據(jù)

整章知識(shí)架構(gòu)

一 、時(shí)間序列中的基本對(duì)象

時(shí)間戳鳞青,即'2020-9-7 08:00:00'和'2020-9-7 10:00:00'這兩個(gè)時(shí)間點(diǎn)分別代表了上課和下課的時(shí)刻霸饲,在pandas中稱(chēng)為T(mén)imestamp。同時(shí)臂拓,一系列的時(shí)間戳可以組成DatetimeIndex厚脉,而將它放到Series中后,Series的類(lèi)型就變?yōu)榱薲atetime64[ns]胶惰,如果有涉及時(shí)區(qū)則為datetime64[ns, tz]傻工,其中tz是timezone的簡(jiǎn)寫(xiě)。

時(shí)間差孵滞,即上課需要的時(shí)間精钮,兩個(gè)Timestamp做差就得到了時(shí)間差,pandas中利用Timedelta來(lái)表示剃斧。類(lèi)似的轨香,一系列的時(shí)間差就組成了TimedeltaIndex, 而將它放到Series中后幼东,Series的類(lèi)型就變?yōu)榱藅imedelta64[ns]臂容。

時(shí)間段科雳,即在8點(diǎn)到10點(diǎn)這個(gè)區(qū)間都會(huì)持續(xù)地在上課,在pandas利用Period來(lái)表示脓杉。類(lèi)似的糟秘,一系列的時(shí)間段就組成了PeriodIndex, 而將它放到Series中后球散,Series的類(lèi)型就變?yōu)榱薖eriod尿赚。

日期偏置,假設(shè)你只知道9月的第一個(gè)周一早上8點(diǎn)要去上課蕉堰,但不知道具體的日期凌净,那么就需要一個(gè)類(lèi)型來(lái)處理此類(lèi)需求。再例如屋讶,想要知道2020年9月7日后的第30個(gè)工作日是哪一天涯捻,那么時(shí)間差就解決不了你的問(wèn)題毯盈,從而pandas中的DateOffset就出現(xiàn)了嗜闻。同時(shí)乏冀,pandas中沒(méi)有為一列時(shí)間偏置專(zhuān)門(mén)設(shè)計(jì)存儲(chǔ)類(lèi)型,理由也很簡(jiǎn)單乐疆,因?yàn)樾枨蟊容^奇怪划乖,一般來(lái)說(shuō)我們只需要對(duì)一批時(shí)間特征做一個(gè)統(tǒng)一的特殊日期偏置。

data type

二挤土、時(shí)間戳

時(shí)間戳

Timestamp的構(gòu)造與屬性

  • 單個(gè)時(shí)間戳:使用pd.Timestamp
ts = pd.Timestamp('2020/1/1')
ts = pd.Timestamp('2020-1-1 08:10:30')
  • 可以通過(guò)year琴庵, month, day耕挨, hour细卧, min, second獲取具體的數(shù)值

Datetime序列的生成

  • to_datetime筒占,能夠把一列時(shí)間戳格式的對(duì)象轉(zhuǎn)換成為datetime64[ns]類(lèi)型的時(shí)間序列:
pd.to_datetime(['2020-1-1', '2020-1-3', '2020-1-6'])
# 可使用format進(jìn)行格式匹配
temp = pd.to_datetime(['2020\\1\\1','2020\\1\\3'],format='%Y\\%m\\%d')
  • date_range
    • start:開(kāi)始時(shí)間
    • end:結(jié)束時(shí)間
    • freq:時(shí)間間隔
    • periods:時(shí)間戳個(gè)數(shù)
pd.date_range('2020-1-1','2020-2-28', freq='10D')

【練一練】

Timestamp上定義了一個(gè)value屬性贪庙,其返回的整數(shù)值代表了從1970年1月1日零點(diǎn)到給定時(shí)間戳相差的納秒數(shù),請(qǐng)利用這個(gè)屬性構(gòu)造一個(gè)隨機(jī)生成給定日期區(qū)間內(nèi)日期序列的函數(shù)翰苫。

def rand_date(date_interval, size=10):
    start = pd.Timestamp(date_interval[0]).value / 10**9 # 單位轉(zhuǎn)換成s
    end = pd.Timestamp(date_interval[1]).value / 10**9 # 單位轉(zhuǎn)換成s
    rand = np.random.randint(start, end+1, size=size)
    return pd.to_datetime(rand, unit='s')

rand_date(['2020-1-1', '2020-2-1'])
answer

asfreq止邮, 對(duì)給定的序列進(jìn)行類(lèi)似于reindex操作

s = pd.Series(np.random.rand(5), index=pd.to_datetime(['2020-1-%d'%i for i in range(1,10,2)]))
s.asfreq('12H')

【練一練】

前面提到了datetime64[ns]本質(zhì)上可以理解為一個(gè)大整數(shù),對(duì)于一個(gè)該類(lèi)型的序列奏窑,可以使用max, min, mean导披,來(lái)取得最大時(shí)間戳、最小時(shí)間戳和“平均”時(shí)間戳埃唯。

date  =rand_date(['2020-1-1', '2020-2-1'], size=100) # 隨機(jī)生成100個(gè)日期
print(date.max()) # 最大值
print(date.min()) # 最小值
print(date.mean()) # 平均值
answer

dt對(duì)象撩匕,如同category, string的序列上定義了cat, str來(lái)完成分類(lèi)數(shù)據(jù)和文本數(shù)據(jù)的操作,在時(shí)序類(lèi)型的序列上定義了dt對(duì)象來(lái)完成許多時(shí)間序列的相關(guān)操作墨叛。

  • 取出時(shí)間相關(guān)的屬性:date, time, year, month, day, hour, minute, second, microsecond, nanosecond, dayofweek, dayofyear, weekofyear, daysinmonth, quarter
  • 判斷時(shí)間戳是否滿足條件
s.dt.is_year_start # 還可選 is_quarter/month_start
s.dt.is_year_end # 還可選 is_quarter/month_end
  • 取整操作
s.dt.round('1H')
s.dt.ceil('1H')
s.dt.floor('1H')

時(shí)間戳的切片與索引

  • 利用dt對(duì)象和布爾條件聯(lián)合使用
s[(idx.is_month_start|idx.is_month_end).values].head()
  • 利用切片止毕,常用于連續(xù)時(shí)間戳
s['2020-05':'2020-7-15']

三模蜡、時(shí)間差

時(shí)間差

Timedelta的生成

  • 單個(gè), 通過(guò)pd.Timedelta
pd.Timestamp('20200102 08:00:00')-pd.Timestamp('20200101 07:35:00')
pd.Timedelta('1 days 25 minutes') # 字符串生成
  • 序列扁凛,通過(guò)pd.to_timedelta, 或timedelta_range
s = pd.to_timedelta(df.Time_Record)
pd.timedelta_range('0s', '1000s', freq='6min')
pd.timedelta_range('0s', '1000s', periods=3)
  • Timedelta序列也定義了dt對(duì)象忍疾,屬性包括days, seconds, mircroseconds, nanoseconds,它們分別返回了對(duì)應(yīng)的時(shí)間差特征谨朝。需要注意的是卤妒,這里的seconds不是指單純的秒,而是對(duì)天數(shù)取余后剩余的秒數(shù)

Timedelta的運(yùn)算

  • 與標(biāo)量的乘法運(yùn)算
  • 與時(shí)間戳的加減法運(yùn)算
  • 與時(shí)間差的加減法與除法運(yùn)算

四字币、日期偏置

日期偏置

Offset對(duì)象则披,在pd.offsets中被定義。當(dāng)使用+時(shí)獲取離其最近的下一個(gè)日期纬朝,當(dāng)使用-時(shí)獲取離其最近的上一個(gè)日期

  • CDay收叶,其中的holidays, weekmask參數(shù)能夠分別對(duì)自定義的日期和星期進(jìn)行過(guò)濾骄呼,前者傳入了需要過(guò)濾的日期列表共苛,后者傳入的是三個(gè)字母的星期縮寫(xiě)構(gòu)成的星期字符串,其作用是只保留字符串中出現(xiàn)的星期
pd.Timestamp('20200831') - pd.offsets.WeekOfMonth(week=0,weekday=0)
pd.Timestamp('20200907') - pd.offsets.BDay(30)
pd.Timestamp('20200907') + pd.offsets.MonthEnd()
my_filter = pd.offsets.CDay(n=1,weekmask='Wed Fri',holidays=['20200109'])
dr = pd.date_range('20200108', '20200111')
dr.to_series().dt.dayofweek

偏置字符串

pd.date_range('20200101','20200331', freq='MS') # 月初
pd.date_range('20200101','20200331', freq='M') # 月末
pd.date_range('20200101','20200110', freq='B') # 工作日
pd.date_range('20200101','20200201', freq='W-MON') # 周一
pd.date_range('20200101','20200201', freq='WOM-1MON') # 每月第一個(gè)周一

五蜓萄、時(shí)序中的滑窗與分組

時(shí)序中的滑窗與分組

滑動(dòng)窗口隅茎,所謂時(shí)序的滑窗函數(shù),即把滑動(dòng)窗口用freq關(guān)鍵詞代替

import matplotlib.pyplot as plt
idx = pd.date_range('20200101', '20201231', freq='B')
np.random.seed(2020)
data = np.random.randint(-1,2,len(idx)).cumsum() # 隨機(jī)游動(dòng)構(gòu)造模擬序列
s = pd.Series(data,index=idx)
s.head()

重采樣嫉沽,重采樣對(duì)象resample和第四章中分組對(duì)象groupby的用法類(lèi)似辟犀,前者是針對(duì)時(shí)間序列的分組計(jì)算而設(shè)計(jì)的分組對(duì)象

s.resample('7min', origin='start').mean().head()

六、練習(xí)

Ex1:太陽(yáng)輻射數(shù)據(jù)集

現(xiàn)有一份關(guān)于太陽(yáng)輻射的數(shù)據(jù)集:

df = pd.read_csv('../data/solar.csv', usecols=['Data','Time','Radiation','Temperature'])
df.head(3)
data
  1. Datetime, Time合并為一個(gè)時(shí)間列Datetime绸硕,同時(shí)把它作為索引后排序堂竟。
  2. 每條記錄時(shí)間的間隔顯然并不一致,請(qǐng)解決如下問(wèn)題:
  • 找出間隔時(shí)間的前三個(gè)最大值所對(duì)應(yīng)的三組時(shí)間戳玻佩。
  • 是否存在一個(gè)大致的范圍出嘹,使得絕大多數(shù)的間隔時(shí)間都落在這個(gè)區(qū)間中?如果存在咬崔,請(qǐng)對(duì)此范圍內(nèi)的樣本間隔秒數(shù)畫(huà)出柱狀圖税稼,設(shè)置bins=50
  1. 求如下指標(biāo)對(duì)應(yīng)的Series
  • 溫度與輻射量的6小時(shí)滑動(dòng)相關(guān)系數(shù)
  • 以三點(diǎn)垮斯、九點(diǎn)郎仆、十五點(diǎn)、二十一點(diǎn)為分割兜蠕,該觀測(cè)所在時(shí)間區(qū)間的溫度均值序列
  • 每個(gè)觀測(cè)6小時(shí)前的輻射量(一般而言不會(huì)恰好取到扰肌,此時(shí)取最近時(shí)間戳對(duì)應(yīng)的輻射量)
# 合并為Datetime,作為索引后排序
Datetime = pd.to_datetime(df.Data) + pd.to_timedelta(df.Time)
df_op = df.drop(['Data', 'Time'], axis=1).set_index(Datetime)
df_op.rename_axis(index='Datetime', inplace=True)
df_op.sort_values('Datetime', inplace=True)
df_op.head()
result1
# 找出間隔時(shí)間的前三個(gè)最大值對(duì)應(yīng)的三組時(shí)間戳
Datetime = pd.Series(df_op.index)
index = Datetime.diff(1).sort_values(ascending=False).head(3).index
df_op.iloc[[index[0]-1, index[0], index[1]-1, index[1], index[2]-1, index[2]]]
result2
delta = pd.to_timedelta(Datetime.diff(1))
delta.quantile(0.01)
cond1 = delta > delta.quantile(0.01)
cond2 = delta < delta.quantile(0.99)
delta.loc[(cond1 & cond2)].astype('timedelta64[s]').plot.hist(bins=50)
result3
# 6小時(shí)滑動(dòng)相關(guān)系數(shù)
r1 = df_op.Radiation.rolling('6H')
r1.corr(df_op.Temperature).head(10)
result4
# 溫度均值
df_op.Temperature.resample('6H', origin='2016-09-01 03:00:00').mean()
result5

Ex2:水果銷(xiāo)量數(shù)據(jù)集

現(xiàn)有一份2019年每日水果銷(xiāo)量記錄表:

df = pd.read_csv('../data/fruit.csv')
df.head(3)
data
  1. 統(tǒng)計(jì)如下指標(biāo):
  • 每月上半月(15號(hào)及之前)與下半月葡萄銷(xiāo)量的比值
  • 每月最后一天的生梨銷(xiāo)量總和
  • 每月最后一天工作日的生梨銷(xiāo)量總和
  • 每月最后五天的蘋(píng)果銷(xiāo)量均值
  1. 按月計(jì)算周一至周日各品種水果的平均記錄條數(shù)熊杨,行索引外層為水果名稱(chēng)曙旭,內(nèi)層為月份墩剖,列索引為星期。
  2. 按天計(jì)算向前10個(gè)工作日窗口的蘋(píng)果銷(xiāo)量均值序列夷狰,非工作日的值用上一個(gè)工作日的結(jié)果填充岭皂。
df.Date = pd.to_datetime(df.Date)
df.set_index('Date', inplace=True)
df.head()
def process(group):
    ret = pd.Series(data=np.zeros(4), index=['葡萄銷(xiāo)量比值', '最后一天梨銷(xiāo)量', '最后工作日梨銷(xiāo)量', '最后五天蘋(píng)果均值'])
    # 上半月與下半月的葡萄銷(xiāo)量的比值
    date = pd.to_datetime(group.index).to_series()
    Grape = group.Fruit == 'Grape'
    ret['葡萄銷(xiāo)量比值'] = group.loc[(date.dt.day<=15 & Grape), 'Sale'].sum() / group.loc[(date.dt.day>15 & Grape), 'Sale'].sum()
    # 每月最后一天的省梨銷(xiāo)量總和
    Pear = group.Fruit == 'Pear'
    ret['最后一天梨銷(xiāo)量'] = group.loc[(date.dt.is_month_end & Pear), 'Sale'].sum()
    # 每月最后一天工作日的省梨銷(xiāo)量總和
    workday = ~(date.dt.weekday.isin([5,6]))
    lastworkday = date.dt.day.loc[workday].max()
    ret['最后工作日梨銷(xiāo)量'] = group.loc[((date.dt.day == lastworkday)  & Pear), 'Sale'].sum()
    # 每月最后五天的蘋(píng)果銷(xiāo)量均值
    day = date.dt.day.unique()
    day.sort()
    Apple = group.Fruit == 'Apple'
    ret['最后五天蘋(píng)果均值'] = group.loc[((date.dt.day.isin(day[-5:]))  & Apple), 'Sale'].mean()
    return ret
df.resample('1M').apply(process).head()
result1
month_order = ['January','February','March','April','May','June','July','August','September','October','November','December']
week_order = ['Mon','Tue','Wed','Thu','Fri','Sat','Sum']
df = df.reset_index()
group1 = df.Fruit
group2 = df.Date.dt.month_name().astype('category').cat.reorder_categories(month_order, ordered=True)
group3 = df.Date.dt.dayofweek.replace(dict(zip(range(7),week_order))).astype('category').cat.reorder_categories(week_order, ordered=True)
res = df.groupby([group1, group2,group3])['Sale'].count().to_frame().unstack(2).droplevel(0,axis=1)
res.head()
result2
df_apple = df[(df.Fruit=='Apple')&(~df.Date.dt.dayofweek.isin([5,6]))]
s = pd.Series(df_apple.Sale.values,index=df_apple.Date).groupby('Date').sum()
res = s.rolling('10D').mean().reindex(pd.date_range('20190101','20191231')).fillna(method='ffill')
res.head()
result3
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沼头,隨后出現(xiàn)的幾起案子爷绘,更是在濱河造成了極大的恐慌,老刑警劉巖进倍,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件土至,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡猾昆,警方通過(guò)查閱死者的電腦和手機(jī)陶因,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)垂蜗,“玉大人楷扬,你說(shuō)我怎么就攤上這事√” “怎么了烘苹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)片部。 經(jīng)常有香客問(wèn)我镣衡,道長(zhǎng),這世上最難降的妖魔是什么档悠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任廊鸥,我火速辦了婚禮,結(jié)果婚禮上辖所,老公的妹妹穿的比我還像新娘惰说。我一直安慰自己,他們只是感情好奴烙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布助被。 她就那樣靜靜地躺著,像睡著了一般切诀。 火紅的嫁衣襯著肌膚如雪揩环。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天幅虑,我揣著相機(jī)與錄音丰滑,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛褒墨,可吹牛的內(nèi)容都是我干的炫刷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼郁妈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼浑玛!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起噩咪,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤顾彰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后胃碾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涨享,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年仆百,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厕隧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俄周,死狀恐怖吁讨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栈源,我是刑警寧澤挡爵,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布竖般,位于F島的核電站甚垦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涣雕。R本人自食惡果不足惜艰亮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挣郭。 院中可真熱鬧迄埃,春花似錦、人聲如沸兑障。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)流译。三九已至逞怨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間福澡,已是汗流浹背叠赦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留革砸,地道東北人除秀。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓糯累,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親册踩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泳姐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容