【時間序列】時間序列建模的時間戳與時序特征衍生思路
特征錦囊:時間序列建模的時間戳與時序特征衍生思路
時間序列模型在我們?nèi)粘9ぷ髦袘?yīng)用的場景還是會很多的,比如我們?nèi)ヮA(yù)測未來的銷售單量、預(yù)測股票價格、預(yù)測期貨走勢、預(yù)測酒店入住等等,這也是我們必須要掌握時序建模的原因。而關(guān)于時間戳以及時序值的特征衍生,在建模過程中起到的作用是十分巨大的!之前寫過一篇關(guān)于日期特征操作的文章——《關(guān)于日期特征,你想知道操作都在這兒~》,可以先回顧下,里面有關(guān)于日期特征的基礎(chǔ)操作手法。
?? Index
01 時間序列數(shù)據(jù)類別簡介
02 時間戳的衍生思路
03 時間戳的衍生代碼分享
04 時序值的衍生思路
05 時序值的衍生代碼分享
?? 01 時間序列數(shù)據(jù)類別簡介
我們就拿經(jīng)典的時間序列模型來說一下,一般來說數(shù)據(jù)集里的數(shù)據(jù),可以分為3大類。
1)Y值:我們也稱之為時序值。如下表中的銷量字段;
2)時間戳:標(biāo)記本條記錄發(fā)生時間的字段,如下表中的統(tǒng)計日期字段。oh,對了如果不是單時間序列的,比如數(shù)據(jù)集中記錄的是多家店鋪的時序數(shù)據(jù),需要結(jié)合序列屬性信息,比如店鋪名稱、店鋪所在城市;
3)其他字段:顧名思義。
而我們今天關(guān)注的是時間戳和時序值的特征衍生。
?? 02 時間戳的衍生思路
雖然時間戳就只有1個字段,但里面其實包含的信息量還是很多的,一般來說我們可以從下面幾個角度來拆解,衍生出一系列的變量。
1)時間戳本身特征
直接使用Pandas的series提取時間戳特征,比如說哪年、哪季度、哪月、哪周、哪日、哪時、哪分、哪秒、年里的第幾天、月里的第幾天、周里的第幾天。
2)0-1特征
一般是與真實場景結(jié)合來用,比如說工作日、周末、公眾假日(春節(jié)、端午節(jié)、中秋節(jié)等)、X初、X中、X末(X代表年、季度、月、周)、特殊節(jié)日(如運營暫停、服務(wù)暫停)、日常習(xí)慣叫法(如清晨、上午、中午、下午、傍晚、夜晚、深夜、凌晨),從而可以衍生出:
是否工作日 是否春節(jié) 是否月初 是否服務(wù)期外 是否凌晨 等等等等
3)時間差特征
一般也是與真實場景結(jié)合來用,比如說工作日、周末等等,比如:
距離春節(jié)還有N天 距離周末還有N天 舉例下月初還有N天 等等等等
?? 03 時間戳的衍生代碼分享
首先我們捏造一些數(shù)據(jù),用來測試代碼。
#?導(dǎo)入相關(guān)庫包
import?pandas?as?pd
import?numpy?as?np
import?datetime
import?time
import?random
from?calendar?import?monthrange?
#?捏造數(shù)據(jù)
df?=?pd.DataFrame(
??????[['零售店01',?'2021-10-01',?'2021-10-01?11:47:34',?'1993-11-03',?'深圳',?100],
???????['零售店01',?'2021-10-02',?'2021-10-02?12:47:34',?'1993-11-04',?'深圳',?120],
???????['零售店01',?'2021-10-03',?'2021-10-03?11:47:34',?'1993-10-03',?'深圳',?140],
???????['零售店01',?'2021-10-04',?'2021-10-04?08:47:34',?'1993-02-03',?'深圳',?170],
???????['零售店01',?'2021-10-05',?'2021-10-05?11:47:34',?'1993-02-03',?'深圳',?190],
???????['零售店01',?'2021-10-06',?'2021-10-06?15:47:34',?'1993-04-03',?'深圳',?10],
???????['零售店01',?'2021-10-07',?'2021-10-07?17:47:34',?'1993-02-03',?'深圳',?20],
???????['零售店01',?'2021-10-08',?'2021-10-08?19:47:34',?'1993-06-03',?'深圳',?420],
???????['零售店01',?'2021-10-09',?'2021-10-09?11:47:34',?'1993-03-03',?'深圳',?230],
???????['零售店01',?'2021-10-10',?'2021-10-10?20:47:34',?'1993-02-20',?'深圳',?80]
??????]
??????,columns=['店鋪名稱',?'統(tǒng)計日期',?'大促開始時間',?'店長出生日期',?'店鋪所在城市',?'銷量'])
df.head()

1)時間戳本身特征
這個就是提取datetime本身的實體特征,利用Pandas的Series方法即可。
#?原先屬于字符串,轉(zhuǎn)datetime
df['datetime64']?=?pd.to_datetime(df['統(tǒng)計日期'])
df['year']?=?df['datetime64'].dt.year
df['quarter']?=?df['datetime64'].dt.quarter
df['month']?=?df['datetime64'].dt.month
df['week']?=?df['datetime64'].dt.week
df['day']?=?df['datetime64'].dt.day
df['hour']?=?df['datetime64'].dt.hour
df['minute']?=?df['datetime64'].dt.minute
df['second']?=?df['datetime64'].dt.second
df['weekday']?=?df['datetime64'].dt.weekday
df['weekofyear']?=?df['datetime64'].dt.weekofyear
df['dayofyear']?=?df['datetime64'].dt.dayofyear
df['dayofweek']?=?df['datetime64'].dt.dayofweek
2)0-1特征
這里我們需要引入一些關(guān)于真實場景的日期來結(jié)合著判斷是否。
df['is_work_day']?=?np.where(df['dayofweek'].isin([5,6]),?0,?1)?#?是否工作日
df['is_month_start']?=?np.where(df['datetime64'].dt.is_month_start,?1,?0)
df['is_month_end']?=?np.where(df['datetime64'].dt.is_month_end,?1,?0)
#?特殊日子/公眾假日
special_day?=?['2021-10-01','2021-10-02']
df['is_special_day']?=?np.where(df['統(tǒng)計日期'].isin(special_day),?1,?0)
#?是否凌晨
df['is_before_dawn']?=?np.where(df['hour'].isin([0,1,2,3]),?1,?0)
3)時間差特征
#?獲取前一天日期
df['yesterday']?=?df['datetime64']?-?datetime.timedelta(days=1)
#?日期差計算(天)
df['day_dif']?=?(df['datetime64']?-?df['yesterday']).dt.days
#?日期差計算(小時)
df['hour_dif']?=?(df['datetime64']?-?df['yesterday']).values/np.timedelta64(1,?'h')?#?換成?D?則為?天

?? 04 時序值的衍生思路
本例中的時序值是銷量字段,一般我們在對時序值進行操作前,需要對數(shù)據(jù)的時序進行排序和補全,然后才開始操作,時序值的特征衍生主要有幾個角度。
1)時間滑動窗口統(tǒng)計
基于某段時間窗,統(tǒng)計數(shù)據(jù)情況,也叫做Rolling Window Statistics,統(tǒng)計的方式一般有min/max/mean/median/std/sum等,比如我們選擇滑動窗口為7天,那么可以衍生的變量分別是:過去7天內(nèi)銷量最小值/最大值/均值/中位數(shù)/方差/之和。
在使用此類特征的時候,要注意一下多步預(yù)測的問題。
2)lag滯后值
lag可以理解為向前滑動時間,比如lag1表示向前滑動1天,即取T-1的時序值作為當(dāng)前時序的變量。
?? 05 時序值的衍生代碼分享
1)時間滑動窗口統(tǒng)計
因為方法叫做Rolling Window Statistics,所以代碼里關(guān)于這塊的實現(xiàn)也有1個叫rolling的方法,這個方法在時序建模中很好用,后面單獨一篇文章講下。
df?=?df.loc[:,['店鋪名稱',?'統(tǒng)計日期','銷量']]
df['date']?=?pd.to_datetime(df['統(tǒng)計日期'])
#?時序值特征衍生前記得排序
df.sort_values(['店鋪名稱',?'統(tǒng)計日期'],?ascending=[True,True],?inplace=True)
#?衍生時間滑動窗口統(tǒng)計變量
f_min?=?lambda?x:?x.rolling(window=3,?min_periods=1).min()
f_max?=?lambda?x:?x.rolling(window=3,?min_periods=1).max()
f_mean?=?lambda?x:?x.rolling(window=3,?min_periods=1).mean()
f_std?=?lambda?x:?x.rolling(window=3,?min_periods=1).std()
f_median=lambda?x:?x.rolling(window=3,?min_periods=1).median()
function_list?=?[f_min,?f_max,?f_mean,?f_std,f_median]
function_name?=?['min',?'max',?'mean',?'std','median']
for?i?in?range(len(function_list)):
????df[('stat_%s'?%?function_name[i])]?=?df.sort_values('統(tǒng)計日期',?ascending=True).groupby(['店鋪名稱'])['銷量'].apply(function_list[i])
2)lag滯后值
#?衍生lag變量
for?i?in?[1,2,3]:
????df["lag_{}".format(i)]?=?df['銷量'].shift(i)

?? Reference
[1] 一度讓我懷疑人生的時間戳特征處理技巧。
https://mp.weixin.qq.com/s/dUdGhWY8l77f1TiPsnjMQA
[2] 時間序列樹模型特征工程匯總
https://blog.csdn.net/fitzgerald0/article/details/104029842
[3] 時間序列的多步預(yù)測方法總結(jié)
https://zhuanlan.zhihu.com/p/390093091
[4] 時間序列數(shù)據(jù)的特征工程總結(jié)
https://zhuanlan.zhihu.com/p/388551117
[5] Pandas Series dt
https://pandas.pydata.org/docs/reference/api/pandas.Series.dt.date.html
往期精彩回顧
