在本文中将探索各種方法來揭示時間序列資料中的異常模式和異常值。
時間序列資料是按一定時間間隔記錄的一系列觀測結果。它經常在金融、天氣預報、股票市場分析等各個領域遇到。分析時間序列資料可以提供有價值的見解,并有助于做出明智的決策。
異常檢測是識别資料中不符合預期行為的模式的過程。在時間序列資料的上下文中,異常可以表示偏離正常模式的重大事件或異常值。檢測時間序列資料中的異常對于各種應用至關重要,包括欺詐檢測、網絡監控和預測性維護。
首先導入庫,為了友善資料擷取,我們直接使用yfinance:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import yfinance as yf
# Download time series data using yfinance
data = yf.download('AAPL', start='2018-01-01', end='2023-06-30')
了解時間序列資料
在深入研究異常檢測技術之前,先簡單介紹時間序列資料的特征。時間序列資料通常具有以下屬性:
- 趨勢:資料值随時間的長期增加或減少。
- 季節性:以固定間隔重複的模式或循環。
- 自相關:目前觀測值與先前觀測值之間的相關性。
- 噪聲:資料中的随機波動或不規則。
讓我們可視化下載下傳的時間序列資料
# Plot the time series data
plt.figure(figsize=(12, 6))
plt.plot(data['Close'])
plt.xlabel('Date')
plt.ylabel('Closing Price')
plt.title('AAPL Stock Price')
plt.xticks(rotation=45)
plt.grid(True)
plt.show()
從圖中可以觀察到股票價格随時間增長的趨勢。也有周期性波動,表明季節性的存在。連續收盤價之間似乎存在一些自相關性。
時間序列資料預處理
在應用異常檢測技術之前,對時間序列資料進行預處理是至關重要的。預處理包括處理缺失值、平滑資料和去除異常值。
缺失值
由于各種原因,如資料收集錯誤或資料中的空白,時間序列資料中可能出現缺失值。适當地處理缺失值以避免分析中的偏差是必要的。
# Check for missing values
missing_values = data.isnull().sum()
print(missing_values)
我們使用的股票資料資料不包含任何缺失值。如果存在缺失值,可以通過輸入缺失值或删除相應的時間點來處理它們。
平滑資料
對時間序列資料進行平滑處理有助于減少噪聲并突出顯示潛在的模式。平滑時間序列資料的一種常用技術是移動平均線。
# Smooth the time series data using a moving average
window_size = 7
data['Smoothed'] = data['Close'].rolling(window_size).mean()
# Plot the smoothed data
plt.figure(figsize=(12, 6))
plt.plot(data['Close'], label='Original')
plt.plot(data['Smoothed'], label='Smoothed')
plt.xlabel('Date')
plt.ylabel('Closing Price')
plt.title('AAPL Stock Price (Smoothed)')
plt.xticks(rotation=45)
plt.legend()
plt.grid(True)
plt.show()
該圖顯示了原始收盤價和使用移動平均線獲得的平滑版本。平滑有助于整體趨勢的可視化和減少短期波動的影響。
去除離群值
異常異常值會顯著影響異常檢測算法的性能。在應用異常檢測技術之前,識别和去除異常值是至關重要的。
# Calculate z-scores for each data point
z_scores = (data['Close'] - data['Close'].mean()) / data['Close'].std()
# Define a threshold for outlier detection
threshold = 3
# Identify outliers
outliers = data[np.abs(z_scores) > threshold]
# Remove outliers from the data
data = data.drop(outliers.index)
# Plot the data without outliers
plt.figure(figsize=(12, 6))
plt.plot(data['Close'])
plt.xlabel('Date')
plt.ylabel('Closing Price')
plt.title('AAPL Stock Price (Without Outliers)')
plt.xticks(rotation=45)
plt.grid(True)
plt.show()
上圖顯示了去除識别的異常值後的時間序列資料。通過減少極值的影響,去除異常值有助于提高異常檢測算法的準确性。
有人會說了,我們不就是要檢測異常值嗎,為什麼要将它删除呢?這是因為,我們這裡删除的異常值是非常明顯的值,也就是說這個預處理是初篩,或者叫粗篩。把非常明顯的值删除,這樣模型可以更好的判斷哪些難判斷的值。
統計方法
統計方法為時間序列資料的異常檢測提供了基礎。我們将探讨兩種常用的統計技術:z-score和移動平均。
z-score
z-score衡量的是觀察值離均值的标準差數。通過計算每個資料點的z分數,我們可以識别明顯偏離預期行為的觀測值。
# Calculate z-scores for each data point
z_scores = (data['Close'] - data['Close'].mean()) / data['Close'].std()
# Plot the z-scores
plt.figure(figsize=(12, 6))
plt.plot(z_scores)
plt.xlabel('Date')
plt.ylabel('Z-Score')
plt.title('Z-Scores for AAPL Stock Price')
plt.xticks(rotation=45)
plt.axhline(y=threshold, color='r', linestyle='--', label='Threshold')
plt.axhline(y=-threshold, color='r', linestyle='--')
plt.legend()
plt.grid(True)
plt.show()
該圖顯示了每個資料點的計算z-score。z-score高于門檻值(紅色虛線)的觀測值可視為異常。
移動平均線
另一種異常檢測的統計方法是基于移動平均線。通過計算移動平均線并将其與原始資料進行比較,我們可以識别與預期行為的偏差。
# Calculate the moving average
window_size = 7
moving_average = data['Close'].rolling(window_size).mean()
# Calculate the deviation from the moving average
deviation = data['Close'] - moving_average
# Plot the deviation
plt.figure(figsize=(12, 6))
plt.plot(deviation)
plt.xlabel('Date')
plt.ylabel('Deviation')
plt.title('Deviation from Moving Average')
plt.xticks(rotation=45)
plt.axhline(y=0, color='r', linestyle='--', label='Threshold')
plt.legend()
plt.grid(True)
plt.show()
該圖顯示了每個資料點與移動平均線的偏差。正偏差表示值高于預期行為,而負偏差表示值低于預期行為。
機器學習方法
機器學習方法為時間序列資料的異常檢測提供了更先進的技術。我們将探讨兩種流行的機器學習算法:孤立森林和LSTM Autoencoder。
孤立森林
孤立森林是一種無監督機器學習算法,通過将資料随機劃分為子集來隔離異常。它測量隔離觀察所需的平均分區數,而異常情況預計需要更少的分區。
from sklearn.ensemble import IsolationForest
# Prepare the data for Isolation Forest
X = data['Close'].values.reshape(-1, 1)
# Train the Isolation Forest model
model = IsolationForest(contamination=0.05)
model.fit(X)
# Predict the anomalies
anomalies = model.predict(X)
# Plot the anomalies
plt.figure(figsize=(12, 6))
plt.plot(data['Close'])
plt.scatter(data.index, data['Close'], c=anomalies, cmap='cool', label='Anomaly')
plt.xlabel('Date')
plt.ylabel('Closing Price')
plt.title('AAPL Stock Price with Anomalies (Isolation Forest)')
plt.xticks(rotation=45)
plt.legend()
plt.grid(True)
plt.show()
該圖顯示了由孤立森林算法識别的異常時間序列資料。異常用不同的顔色突出顯示,表明它們偏離預期行為。
LSTM Autoencoder
LSTM (Long - Short-Term Memory)自編碼器是一種深度學習模型,能夠學習時間序列資料中的模式并重構輸入序列。通過将重建誤差與預定義的門檻值進行比較,可以檢測異常。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
# Prepare the data for LSTM Autoencoder
X = data['Close'].values.reshape(-1, 1)
# Normalize the data
X_normalized = (X - X.min()) / (X.max() - X.min())
# Train the LSTM Autoencoder model
model = Sequential([
LSTM(64, activation='relu', input_shape=(1, 1)),
Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_normalized, X_normalized, epochs=10, batch_size=32)
# Reconstruct the input sequence
X_reconstructed = model.predict(X_normalized)
# Calculate the reconstruction error
reconstruction_error = np.mean(np.abs(X_normalized - X_reconstructed), axis=1)
# Plot the reconstruction error
plt.figure(figsize=(12, 6))
plt.plot(reconstruction_error)
plt.xlabel('Date')
plt.ylabel('Reconstruction Error')
plt.title('Reconstruction Error (LSTM Autoencoder)')
plt.xticks(rotation=45)
plt.axhline(y=threshold, color='r', linestyle='--', label='Threshold')
plt.legend()
plt.grid(True)
plt.show()
該圖顯示了每個資料點的重建誤差。重建誤差高于門檻值(紅色虛線)的觀測值可視為異常。
異常檢測模型的評估
為了準确地評估異常檢測模型的性能,需要有包含有關異常存在或不存在的資訊的标記資料。但是在現實場景中,擷取帶有已知異常的标記資料幾乎不可能,是以可以采用替代技術來評估這些模型的有效性。
最常用的一種技術是交叉驗證,它涉及将可用的标記資料分成多個子集或折疊。模型在資料的一部分上進行訓練,然後在剩餘的部分上進行評估。這個過程重複幾次,并對評估結果進行平均,以獲得對模型性能更可靠的估計。
當标記資料不容易獲得時,也可以使用無監督評估度量。這些名額基于資料本身固有的特征(如聚類或密度估計)來評估異常檢測模型的性能。無監督評價名額的例子包括輪廓系數silhouette score、鄧恩指數Dunn index或平均最近鄰距離。
總結
本文探索了使用機器學習進行時間序列異常檢測的各種技術。首先對其進行預處理,以處理缺失值,平滑資料并去除異常值。然後讨論了異常檢測的統計方法,如z-score和移動平均。最後探讨了包括孤立森林和LSTM自編碼器在内的機器學習方法。
異常檢測是一項具有挑戰性的任務,需要對時間序列資料有深入的了解,并使用适當的技術來發現異常模式和異常值。記住要嘗試不同的算法,微調參數并評估模型的性能,以獲得最佳結果。
作者:AI Quant