?【特征工程】時序特征挖掘的奇技淫巧
最近在做時間序列的項目,所以總結一下構造的特征的方法和一些經驗。
先放上大綱:

1.時間特征
1.1 連續(xù)時間
持續(xù)時間: 瀏覽時長; 間隔時間: 購買/點擊距今時長; 距離假期的前后時長(節(jié)假日前和節(jié)假日后可能會出現明顯的數據波動);
1.2 離散時間
年、季度、季節(jié)、月、星期、日、時 等;
基本特征,如果用 Xgboost 模型可以進行 one-hot 編碼; 如果類別比較多,可以嘗試平均數編碼(Mean Encoding)。 或者取 cos/sin 將數值的首位銜接起來,比如說 23 點與 0 點很近,星期一和星期天很近。 節(jié)假日、節(jié)假日第 n 天、節(jié)假日前 n 天、節(jié)假日后 n 天;
數據可能會隨著節(jié)假日的持續(xù)而發(fā)生變化,比如說遞減; 節(jié)假日前/后可能會出現數據波動; 不放假的人造節(jié)日如 5.20、6.18、11.11 等也需要考慮一下; 一天的某個時間段;
上午、中午、下午、傍晚、晚上、深夜、凌晨等; 年初、年末、月初、月末、周內、周末;
基本特征; 高峰時段、是否上班、是否營業(yè)、是否雙休日;
主要根據業(yè)務場景進行挖掘。
#?年、季度、季節(jié)、月、星期、日、時??
data_df['date']?=?pd.to_datetime(data_df['date'],?format="%m/%d/%y")
data_df['quarter']=data_df['date'].dt.quarter
data_df['month']?=?data_df['date'].dt.month
data_df['day']?=?data_df['date'].dt.day
data_df['dayofweek']?=?data_df['date'].dt.dayofweek
data_df['weekofyear']?=?data_df['date'].dt.week???#?一年中的第幾周
# Series.dt 下有很多屬性,可以去看一下是否有需要的。
data_df['is_year_start']?=?data_df['date'].dt.is_year_start
data_df['is_year_end']?=?data_df['date'].dt.is_year_end
data_df['is_quarter_start']?=?data_df['date'].dt.is_quarter_start
data_df['is_quarter_end']?=?data_df['date'].dt.is_quarter_end
data_df['is_month_start']?=?data_df['date'].dt.is_month_start
data_df['is_month_end']?=?data_df['date'].dt.is_month_end
#?是否時一天的高峰時段 8~10
data_df['day_high']?=?data_df['hour'].apply(lambda?x:?0?if??0?8??else?1)
#?構造時間特征
def?get_time_fe(data,?col,?n,?one_hot=False,?drop=True):
??'''
???data:?DataFrame
???col:?column?name
???n:?時間周期
??'''
??data[col?+?'_sin']?=?round(np.sin(2*np.pi?/?n?*?data[col]),?6)
??data[col?+?'_cos']?=?round(np.cos(2*np.pi?/?n?*?data[col]),?6)
??if?one_hot:
????ohe?=?OneHotEncoder()
????X?=?OneHotEncoder().fit_transform(data[col].values.reshape(-1,?1)).toarray()
????df?=?pd.DataFrame(X,?columns=[col?+?'_'?+?str(int(i))?for?i?in?range(X.shape[1])])
????data?=?pd.concat([data,?df],?axis=1)
????if?drop:
??????data?=?data.drop(col,?axis=1)
???return?data
data_df?=?get_time_fe(data_df,?'hour',?n=24,?one_hot=False,?drop=False)
data_df?=?get_time_fe(data_df,?'day',?n=31,?one_hot=False,?drop=True)
data_df?=?get_time_fe(data_df,?'dayofweek',?n=7,?one_hot=True,?drop=True)
data_df?=?get_time_fe(data_df,?'season',?n=4,?one_hot=True,?drop=True)
data_df?=?get_time_fe(data_df,?'month',?n=12,?one_hot=True,?drop=True)
data_df?=?get_time_fe(data_df,?'weekofyear',?n=53,?one_hot=False,?drop=True)
2.聚合特征
2.1 統(tǒng)計值
基于歷史數據構造長中短期的統(tǒng)計值,包括前 n 天/周期內的:
四分位數; 中位數、平均數、偏差; 偏度、峰度; 挖掘數據的偏離程度和集中程度; 離散系數; 挖掘離散程度
這里可以用自相關系數(autocorrelation)挖掘出周期性。
除了對數據進行統(tǒng)計外,也可以對節(jié)假日等進行統(tǒng)計,以刻畫歷史數據中所含節(jié)假日的情況。(還可以統(tǒng)計未來的節(jié)假日的情況。)
#?畫出自相關性系數圖
from?pandas.plotting?import?autocorrelation_plot
autocorrelation_plot(data['value'])
#?構造過去?n?天的統(tǒng)計數據
def?get_statis_n_days_num(data,?col,?n):
??temp?=?pd.DataFrame()
??for?i?in?range(n):
????temp?=?pd.concat([temp,?data[col].shift((i+1)*24)],?axis=1)
????data['avg_'+?str(n)?+'_days_'?+?col]?=?temp.mean(axis=1)
????data['median_'+?str(n)?+'_days_'?+?col]?=?temp.median(axis=1)
????data['max_'+?str(n)?+'_days_'?+?col]?=?temp.max(axis=1)
????data['min_'+?str(n)?+'_days_'?+?col]?=?temp.min(axis=1)
????data['std_'+?str(n)?+'_days_'?+?col]?=?temp.std(axis=1)
????data['mad_'+?str(n)?+'_days_'?+?col]?=?temp.mad(axis=1)
????data['skew_'+?str(n)?+'_days_'?+?col]?=?temp.skew(axis=1)
????data['kurt_'+?str(n)?+'_days_'?+?col]?=?temp.kurt(axis=1)
????data['q1_'+?str(n)?+'_days_'?+?col]?=?temp.quantile(q=0.25,?axis=1)
????data['q3_'+?str(n)?+'_days_'?+?col]?=?temp.quantile(q=0.75,?axis=1)
????data['var_'+?str(n)?+'_days_'?+?col]?=?data['std_'+?str(n)?+'_days_'?+?col]/data['avg_'+?str(n)?+'_days_'?+?col]??#?離散系數
????return?data
data_df?=?get_statis_n_days_num(data_df,?'num_events',?n=7)
data_df?=?get_statis_n_days_num(data_df,?'num_events',?n=14)
data_df?=?get_statis_n_days_num(data_df,?'num_events',?n=21)
data_df?=?get_statis_n_days_num(data_df,?'num_events',?n=28)
此外,還可以對這些統(tǒng)計值進行分桶,增強模型的魯棒性。
2.2 同期值
前 n 個周期/天/月/年的同期值;
#?n?個星期前同期特征
data_df['ago_7_day_num_events']?=?data_df['num_events'].shift(7*24)
data_df['ago_14_day_num_events']?=?data_df['num_events'].shift(14*24)
data_df['ago_21_day_num_events']?=?data_df['num_events'].shift(21*24)
data_df['ago_28_day_num_events']?=?data_df['num_events'].shift(28*24)
#?昨天的同期特征
data_df['ago_7_day_num_events']?=?data_df['num_events'].shift(1*24)
3.交叉特征
類別特征間組合構成新特征: 笛卡爾積,比如星期和小時:Mon_10(星期一的十點); 類別特征和連續(xù)特征: 連續(xù)特征分桶后進行笛卡爾積; 基于類別特征進行 groupby 操作,類似聚合特征的構造; 連續(xù)特征和連續(xù)特征: 同比和環(huán)比(一階差分):反應同期或上一個統(tǒng)計時段的變換大小; 二階差分:反應變化趨勢; 比值;
特征交叉一般從重要特征線下手,慢工出細活。
#?一階差分
data_df['ago_28_21_day_num_trend']?=?data_df['ago_28_day_num_events']?-?data_df['ago_21_day_num_events']
data_df['ago_21_14_day_num_trend']?=?data_df['ago_21_day_num_events']?-?data_df['ago_14_day_num_events']
data_df['ago_14_7_day_num_trend']?=?data_df['ago_14_day_num_events']?-?data_df['ago_7_day_num_events']
data_df['ago_7_1_day_num_trend']?=?data_df['ago_7_day_num_events']?-?data_df['ago_1_day_num_events']
4.寫在最后
構造時序特征時一定要算好時間窗口,特別是在工作的時候,需要自己去設計訓練集和測試集,千萬不要出現數據泄露的情況(比如說預測明天的數據時,是拿不到今天的特征的); 針對上面的情況,可以嘗試將今天的數據進行補齊; 有些特征加上去效果會變差,大概率是因為過擬合了; 有些特征加上去效果出奇好,第一時間要想到是不是數據泄露了; 擬合不好的時間(比如說雙休日)可以分開建模; ont-hot 對 xgboost 效果的提升很顯著; 離散化對 xgboost 效果的提升也很顯著; 對標簽做個平滑效果可能會顯著提升; 多做數據分析,多清洗數據;
“干貨學習,點贊三連↓
評論
圖片
表情
