循環(huán)編碼:時間序列中周期性特征的一種常用編碼方式
共 4698字,需瀏覽 10分鐘
·
2024-05-15 17:00
來源:Deephub Imba 本文約2500字,建議閱讀5分鐘
本文介紹了時間序列預測或理解展示周期性特征的序列。
在深度學習或神經(jīng)網(wǎng)絡中,"循環(huán)編碼"(Cyclical Encoding)是一種編碼技術,其特點是能夠捕捉輸入或特征中的周期性或循環(huán)模式。這種編碼方法常用于處理具有周期性行為的任務,比如時間序列預測或理解展示周期性特征的序列。
循環(huán)編碼的核心思想是將數(shù)據(jù)的周期性特征轉(zhuǎn)化為網(wǎng)絡能夠理解的形式。例如,在處理時間數(shù)據(jù)時,比如小時、日、月等的循環(huán)模式,可以使用循環(huán)編碼來幫助模型識別和利用這些周期性的變化。
當涉及到訓練時間序列模型時,通常會使用以下時間特征:
小時、星期、月、周或年中的一天
將時間戳列轉(zhuǎn)換為這些類型的特性是相當容易的。在確保將時間列轉(zhuǎn)換為datetime對象(使用pd.to_datetime)之后,可以使用.dt提取一系列時間序列特征。
df['Hour']=df['Datetime'].dt.hour df['Month']=df['Datetime'].dt.month df['Dayofweek']=df['Datetime'].dt.dayofweek
能源消耗數(shù)據(jù)集通常是時間序列,其最終目標是使用過去的數(shù)據(jù)預測未來的消耗,因此這是一個很好的用例。雖然其他外部特征,如溫度、濕度和風速也會影響能耗,但本文將重點關注時間序列特征的提取和轉(zhuǎn)換。
在能源消耗方面,一天中有一定的高峰時段,更有可能出現(xiàn)更高的消耗。也有一些特定的時間往往消耗較少。從某種意義上說,每個小時都有自己的范疇。
放大該數(shù)據(jù)集的特定部分就可以展示這一點。全天都有明確的消費模式——使用量在同一時間(下午5 - 6點)達到峰值,在早上5 - 7點達到最低。
這些模式與其他特征有復雜的交互,例如一年中的時間/月份和一周中的一天,這就是為什么我們希望在模型中包含盡可能多的信息的原因。
傳統(tǒng)編碼的問題
那么我們怎么做呢?如果你像大多數(shù)人一樣,你早就知道分類特征需要以其他格式編碼,以便模型正確地理解它們是什么。最著名的方法是one-hot編碼。
One-hot編碼簡單且易于實現(xiàn)。對于一天(或一個月、一天等)中的任何一個小時,“它是小時/天/月n嗎?”然后用二進制0或1來回答這個問題。它對每種類別都這樣做。因此,對于1 day_of_week原始特征,您將有7個編碼特征(表示一周中的7天):
is_day_1
is_day_2
is_day_3
is_day_4
is_day_5
is_day_6
is_day_7
在Python中,最簡單的方法是使用pd.get_dummies:
columns_to_encode = ['Hour', 'Month', 'Dayofweek'] df = pd.get_dummies(df, columns=columns_to_encode)
這將產(chǎn)生新的特性集。
我們從3個特征(小時、月、日)得到了40多個特征。隨著添加越來越多需要編碼的時間序列特征,這會變得越來越混亂。
循環(huán)編碼
這時候就可以到我們提到的循環(huán)編碼,因為時間序列特征本質(zhì)上是周期性的。以時間為例當時鐘敲響24:00(凌晨12點),新的一天開始,下一個小時是1:00(凌晨1點)。雖然數(shù)字1和24實際上是距離最遠的數(shù)字,但1和23一樣接近24,因為它們在一個循環(huán)中。
另一種用數(shù)字表示時間序列特征的方法是將時間戳轉(zhuǎn)換成正弦和余弦變換。這種方式會告訴你一天中的時間,一周中的時間,或者一年中的時間。
我們需要的編碼不是將日期時間值轉(zhuǎn)換為分類特征(就像我們使用one-hot編碼一樣),而是將它們轉(zhuǎn)換為數(shù)值特征,其中一些值更接近(例如12AM和1AM),而其他值則更遠(例如12AM和12PM)。但當我們用One-hot編碼時,這種信息就丟失了。
正弦和余弦來自單位圓,可以映射時間戳在這個圓上的位置,用正弦和余弦坐標表示。將圓圈的右側視為起點(在下面的圖表中以0表示)或真正的24小時時間刻度上的00:00 (12AM),我們將其劃分為4個6小時的地標,以便能夠?qū)⑿r映射到圓上。
當你在單位圓上逆時針移動時,它增加到/2(或90度),這相當于6:00AM,(180度)或12:00PM, 3 /2或6:00PM,最后在12:00 am回到0。這些時間點都有自己獨特的坐標。這樣就可以用正弦和余弦表示24小時的每日周期。
其他周期也可以這樣做,比如一周或一年的時間,一般的公式如下:
要在Python中完成此操作,需要首先將datetime(在我的示例中是小時時間戳)轉(zhuǎn)換為數(shù)值變量。通過將該列轉(zhuǎn)換為pd.Timestamp.timestamp對象,將每個時間戳轉(zhuǎn)換為unix時間(自1970年1月1日以來經(jīng)過的秒數(shù))。然后把這個數(shù)值列變換成正弦和余弦的特征。
# Convert datetime into a numerical seconds timestamp object # (tells you the date/time in seconds) timestamp_s = df['Datetime'].map(pd.Timestamp.timestamp) # Get the number of seconds for each time period day = 24*60*60 week = day*7 year = day*(365.2425) # Transform using sin and cos # Time of day df['Day_sin'] = np.sin(timestamp_s * (2 * np.pi / day)) df['Day_cos'] = np.cos(timestamp_s * (2 * np.pi / day)) # Time of week df['Week_sin'] = np.sin(timestamp_s * (2 * np.pi / week)) df['Week_cos'] = np.cos(timestamp_s * (2 * np.pi / week)) # Time of year df['Year_sin'] = np.sin(timestamp_s * (2 * np.pi / year)) df['Year_cos'] = np.cos(timestamp_s * (2 * np.pi / year))
上面的代碼解釋如下:首先將時間戳從秒轉(zhuǎn)換為弧度。2 * np.pi 是因為一個完整的圓/周期有2pi的弧度。轉(zhuǎn)換后除以的周期持續(xù)時間(以秒為單位)(日、周或年)。然后就可以將每個時間戳映射到一個唯一的角度,該角度通過乘以弧度數(shù)來表示它在周期中的位置。
如果周期是day,那么一天開始的時間戳將被映射到0弧度,一天中間的時間戳將被映射到np.pi,一天結束時的時間戳將被映射為2 * np.pi 。
最后對計算結果進行sin和cos,得到單位圓上實際的x和y坐標值。這些值總是在-1到1之間。
通過這種方法,每個原始時間序列特征(例如一天中的小時,一周中的一天,一年中的月份)現(xiàn)在只映射到2個新特征(原始特征的sin和cos),而不是24,7,12等。
缺點和注意事項
使用這種方法時一定要小心。雖然它非常方便和高效,但也有一些缺點和注意事項:
1、One-hot編碼可以更好地用于基于特定時間、月份等具有更一致的不同值的數(shù)據(jù)集-例如,數(shù)據(jù)集在中午12點或某個月份達到峰值。而在時間范圍更大的數(shù)據(jù)集(12PM-2PM)中,循環(huán)編碼等方法一般會更準確。
2、這種類型的編碼適用于深度學習/神經(jīng)網(wǎng)絡,但可能不適用于隨機森林這樣的樹分割算法。因為通常表示一個特征的單個時間戳被分割成兩個特征,而基于樹的算法每次只分割一個特征。這兩個特征是對應于一個原始特征的坐標對,而樹形模型可能將它們分開處理。
但是這并不是說你永遠不能對基于樹的算法使用循環(huán)編碼。我實際上在隨機森林模型中使用了這種類型的編碼,并取得了很好的效果。還是我們的老生常談,這將取決于數(shù)據(jù)集,所以在交叉驗證和最終hold out測試集上運行測試是很重要的。
這種編碼方式在各種應用中都非常有用,尤其是在預測和分析涉及明確周期或重復模式的數(shù)據(jù)時。但是在決定使用哪種編碼之前,將編碼結果進行比較是非常重要的。
編輯:王菁
