1. 程式人生 > 其它 >時間序列樹模型特徵工程彙總

時間序列樹模型特徵工程彙總

時間序列特徵彙總
特徵一、時間特徵
特徵二、類別mean encoding特徵
特徵三、統計特徵
特徵四:滯後歷史特徵
特徵五:序列特徵
特徵六:高階特徵
特徵七:外部特徵
稍微總結一下,時間序列中的特徵,主要針對機器學習樹模型,因為是時序資料,所以和尋常的機器學習特徵略有不同,比如關注時間特徵,滯後特徵,滑窗特徵等。

特徵一、時間特徵

import datetime
import pandas as pd
df['ds']=df['ds'].astype(str)
df['ds'] = df['ds'].apply(lambda x: datetime.datetime.strptime(x, "%Y-%m-%d"))
df['year']=df['ds'].dt.year
df['quarter']=df['ds'].dt.quarter
df['month']=df['ds'].dt.month
df['dayofweek']=df['ds'].dt.dayofweek
df['week']=df['ds'].dt.week

諸如此類,更多相信內容請參照一下文件https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html
還有格外需要手工生成的時間段切分:比如講一天分為上午,下午,晚上這樣的特徵,可以使用apply,配合lambda匿名函式

df['half']=df['hour'].apply(lambda x: 1 if x<'12' else 0)
對於出現的異常值,年底出現促銷,導致銷售波動,對該天的資料做異常標記

df['outlier']=df['ds'].apply(lambda x: 1 if x=='2018-12-31' else 0)
還如,定義是否為春節月,是否為月末等,對這類具有明顯銷售波動的帶有時間點打標籤。這部分特徵是十分基礎且重要。

特徵二、類別mean encoding特徵
#針對類別變數可以有如下方法
#Mean Encoding
#比如門店預測
#帶有城市標籤,如果用OneHotEncoder轉換為0-1特徵就太多了
#我們可以使用mean encoding方式,構建均值特徵


city_mean=df.groupby(['city']).agg({'y': ['mean']})
city_mean.reset_index(inplace=True)
city_mean.columns = ['city','city_mean']


#其他的資訊,比如省份等亦是如此


df = pd.merge(df,city_mean,on='city',how='inner')

還有一種類似的count encoding,
其實應該歸於統計特徵
至於實現方式那就是


city_count=df.groupby(['city']).agg({'y': ['count']})

特徵三、統計特徵
如mean, median, max, min, std
需要注意的是windows的選擇
如果是月的話,建議選擇三 如果是日,且有周的規律性,則應該選擇7,也可以同時存在多個顆粒度的滑窗特徵。比如,選擇了滑窗4,同時使用滑窗12,那就是季度。當然你也可是多嘗試,所以調參俠的樂趣/苦逼,也就在這裡了。滑窗也是一種對資料的平滑。一定不要忘記,把資料的順序換過來。


df.sort_values(['store_code','ds'],ascending=[True,True],inplace=True)
f_min = lambda x: x.rolling(window=4, min_periods=1).min()
f_max = lambda x: x.rolling(window=4, min_periods=1).max()
f_mean = lambda x: x.rolling(window=4, min_periods=1).mean()
f_std = lambda x: x.rolling(window=4, min_periods=1).std()
f_median=lambda x: x.rolling(window=4, 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('ds').groupby(['store_code'])['y'].apply(function_list[i])

說明一點,這裡為何沒有使用sum聚合函式,因為有了mean,所以就沒有必要使用sum了,因為sum是可以依據mean求得(可以依據一個特徵直接得到的另一個變數的就屬於冗餘特徵)
還有峰度,偏度等
有一個在時間序列方面非常出名的特徵庫:tsfresh
https://tsfresh.readthedocs.io/en/latest/api/tsfresh.feature_extraction.html
提供了非常多的特徵擴充套件,我在之前的一篇文章中有提到,感興趣的讀者,可以前往一看。
tsfresh已經可以生成這麼多的特徵了,為何我們不直接調包,還要花這麼大的力氣來手工一個一個實現呢?
針對這兩點疑問,有如下解釋,雖然目前計算資源較為充裕,但我們也不希望在模型準確率接近的情況下,一個自動生成了300維度的特徵花費兩個小時,一個自己擴充套件了30維度的特徵花費3分鐘,不斷迭代中的等待時間是非常昂貴的,所以我個人傾向於手工實現,做到心中有數,否則和黑匣子有什麼區別。
其二,我們在很多情況下還是要追求模型的可解釋性,少而精的特徵,對於指導運營人員,具有非常大的價值,需要明白知道特徵的含義。

特徵四:滯後歷史特徵

for i in [1,2,4,8,12,24,52]:
df["lag_{}".format(i)] = df.groupby('store_code')['y'].shift(i)


這樣的形式也是可以的,因為我這裡是周的銷售預測,所以我比較關注,上一週的,上兩週的,四周以前的,也就是一個月前,以及8周,就是兩月前。
這裡是周銷售預測,所以更關注上一週/上兩週/四周前/8周的歷史資料。
以上生成滯後特徵,於是就可以方便的計算同/環比。
需要注意的是,只能是用滯後的資料,不能基於y值生成特徵,否則就是資料穿越了


df['huanbi_1_2'] = df['last_1_sale'] / df['last_2_sale']
df['last_14_2_sale'] = (df['last_14_sale'] - df['last_2_sale']) / df['last_14_sale']
df['sale_uplift'] = (data['last_1_sale'] - data['last_2_sale']) / data['last_2_sale']


特徵五:序列特徵
不太好定義這類特徵名稱,姑且叫著序列特徵
當面對眾多序列的時候,也可以統計時間序列中單個序列的特性,比如,週期性,平穩性,複雜性(eg.排序熵)等等單個時間序列本身具有的資訊。程式碼和具體講解,見個人的另一篇部落格

特徵六:高階特徵
若有更多的資訊,我們是可以利用多個特徵進行融合,比如,我有門店開業時長,平均營業額,門店銷售方差等等,可以利用這些資訊聚類。

理由是:把類別標籤,作為一個特徵,相同的類別,理應具有相似的曲線,具有相似特性的資料,生成相同的資料特徵。

當然有讀者肯定有疑問了,聚類是無監督學習,事先無法知道聚類的個數,這裡建議使用一點經驗值,或者使用聚類的評估指標,如果輪廓係數,得到一個較為可靠的類別數。


def store_cluster(data):
data_.drop_duplicates(subset=['store_code'],inplace=True)
data_un=data_[['store_code','shop_mean','open_length','std_7']].set_index(['store_code'])
data_un.fillna(0, inplace=True)
columns_to_normalize= ['shop_mean','open_length','std_7']
data_un[columns_to_normalize] = data_un[columns_to_normalize].apply(lambda x: (x - x.mean()) / np.std(x))
kmeans= KMeans(n_clusters=4).fit(data_un)
data_un['cluster_id']=kmeans.predict(data_un)
data_un=data_un.reset_index()
return data_un[['store_code','cluster_id']]

剛提到了曲線和趨勢,那麼,我們也是可以依據多條序列的波動,依據波動,找到相似的波動曲線,作為同一類標籤,這就是基於時間序列的一個聚類方式。
比如 DTW方法

如果說KMeans聚類是一種靜態的使用歐式距離計算的聚類方法,DTW方法就是一種對多個序列具有延展或者壓縮特性的度量距離的方法,考慮序列形狀的相似,常用的演算法如k-shape。關於該方法和程式碼見個人更新的另一篇文章。連結

除此之外還有傅立葉變換模組和函式如下:

from pykalman import KalmanFilter

當然對於多個類別資料,也可以使用embedding的方式
https://www.tensorflow.org/tutorials/text/word_embeddings
或者*TF-IDF,總的來說我這裡列舉的高階特徵,是利用多個特徵進行融合,或者使用多條資料,求得相似性,減少資訊冗餘。當然也限於篇幅的原因,這部分非常重要的內容沒有展開來講,不過可以依據以上提到的關鍵詞和資料很容易找到相關材料。

特徵七:外部特徵
很多資料科學競賽本身不提供外部資料,但鼓勵選手通過技術手段獲取並利用外部資料,比如天氣,比如節假日,對氣溫這樣的特徵,做分桶處理見pd.cut函式。

以上就是個人日常使用較多的特徵,只是針對樹模型特徵生成過程進行簡單的總結闡述,具體在建模過程中還要依據資料本身靈活多變,還有諸如,prophet模型的特徵,資料預處理等等內容再次不做介紹,如有機會單獨開篇。
————————————————
版權宣告:本文為CSDN博主「fitzgerald0」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/fitzgerald0/article/details/104029842