使用 Pandas 進(jìn)行時(shí)間序列分析的 11 個(gè)關(guān)鍵點(diǎn)
大家好!今天我們來(lái)聊聊如何用 Pandas 庫(kù)進(jìn)行時(shí)間序列分析。Pandas 是 Python 中最強(qiáng)大的數(shù)據(jù)處理庫(kù)之一,非常適合處理時(shí)間序列數(shù)據(jù)。這篇文章將帶你逐步了解時(shí)間序列分析的基礎(chǔ)知識(shí),以及如何用 Pandas 實(shí)現(xiàn)。
1. 時(shí)間序列數(shù)據(jù)簡(jiǎn)介
時(shí)間序列數(shù)據(jù)是指按照時(shí)間順序排列的數(shù)據(jù)。比如股票價(jià)格、氣溫變化等。時(shí)間序列分析可以幫助我們發(fā)現(xiàn)數(shù)據(jù)中的模式、趨勢(shì)和周期性變化。
示例:
import pandas as pd
# 創(chuàng)建一個(gè)簡(jiǎn)單的 DataFrame
data = {
'Date': ['2022-01-01', '2022-01-02', '2022-01-03'],
'Price': [100, 105, 110]
}
df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)
print(df)
輸出:
Price
Date
2022-01-01 100
2022-01-02 105
2022-01-03 110
2. 設(shè)置日期為索引
為了方便處理時(shí)間序列數(shù)據(jù),通常會(huì)把日期設(shè)置為 DataFrame 的索引。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': ['2022-01-01', '2022-01-02', '2022-01-03'],
'Price': [100, 105, 110]
})
# 將 'Date' 列轉(zhuǎn)換為 datetime 類型
df['Date'] = pd.to_datetime(df['Date'])
# 將 'Date' 設(shè)為索引
df.set_index('Date', inplace=True)
print(df)
輸出:
Price
Date
2022-01-01 100
2022-01-02 105
2022-01-03 110
3. 數(shù)據(jù)重采樣
數(shù)據(jù)重采樣是指將時(shí)間序列數(shù)據(jù)重新調(diào)整到不同的時(shí)間頻率。例如,將日數(shù)據(jù)轉(zhuǎn)換為月數(shù)據(jù)或年數(shù)據(jù)。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),
'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]
})
df.set_index('Date', inplace=True)
# 按月重采樣并計(jì)算平均值
monthly_df = df.resample('M').mean()
print(monthly_df)
輸出:
Price
Date
2022-01-31 122.5
2022-02-28 140.0
4. 插值方法
當(dāng)時(shí)間序列數(shù)據(jù)中有缺失值時(shí),可以使用插值方法填補(bǔ)這些缺失值。Pandas 提供了多種插值方法。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),
'Price': [100, 105, None, 115, 120, 125, 130, 135, 140, 145]
})
df.set_index('Date', inplace=True)
# 使用線性插值填補(bǔ)缺失值
df['Price'] = df['Price'].interpolate()
print(df)
輸出:
Price
Date
2022-01-01 100.0
2022-01-02 105.0
2022-01-03 110.0
2022-01-04 115.0
2022-01-05 120.0
2022-01-06 125.0
2022-01-07 130.0
2022-01-08 135.0
2022-01-09 140.0
2022-01-10 145.0
5. 移動(dòng)平均
移動(dòng)平均是時(shí)間序列分析中常用的方法,可以用來(lái)平滑數(shù)據(jù)、發(fā)現(xiàn)趨勢(shì)。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),
'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]
})
df.set_index('Date', inplace=True)
# 計(jì)算 5 日移動(dòng)平均
df['MA_5'] = df['Price'].rolling(window=5).mean()
print(df)
輸出:
Price MA_5
Date
2022-01-01 100.0 NaN
2022-01-02 105.0 NaN
2022-01-03 110.0 NaN
2022-01-04 115.0 NaN
2022-01-05 120.0 112.000000
2022-01-06 125.0 115.000000
2022-01-07 130.0 118.000000
2022-01-08 135.0 121.000000
2022-01-09 140.0 124.000000
2022-01-10 145.0 127.000000
6. 季節(jié)性分解
季節(jié)性分解可以幫助我們識(shí)別數(shù)據(jù)中的趨勢(shì)、季節(jié)性和隨機(jī)成分。
示例:
from statsmodels.tsa.seasonal import seasonal_decompose
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=365, freq='D'),
'Price': [100 + i + (i % 7) * 5 for i in range(365)]
})
df.set_index('Date', inplace=True)
# 進(jìn)行季節(jié)性分解
result = seasonal_decompose(df['Price'], model='additive')
# 查看分解結(jié)果
print(result.trend)
print(result.seasonal)
print(result.resid)
輸出(部分):
2022-01-01 100.0
2022-01-02 101.0
2022-01-03 102.0
...
2022-12-30 464.0
2022-12-31 465.0
Freq: D, Name: Price, dtype: float64
7. 時(shí)間序列滯后
滯后是指將時(shí)間序列數(shù)據(jù)向后移動(dòng)一定的步長(zhǎng)。這在構(gòu)建時(shí)間序列模型時(shí)非常有用。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),
'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]
})
df.set_index('Date', inplace=True)
# 計(jì)算滯后 1 的列
df['Lag_1'] = df['Price'].shift(1)
print(df)
輸出:
Price Lag_1
Date
2022-01-01 100.0 NaN
2022-01-02 105.0 100.0
2022-01-03 110.0 105.0
2022-01-04 115.0 110.0
2022-01-05 120.0 115.0
2022-01-06 125.0 120.0
2022-01-07 130.0 125.0
2022-01-08 135.0 130.0
2022-01-09 140.0 135.0
2022-01-10 145.0 140.0
8. 自相關(guān)和偏自相關(guān)函數(shù)
自相關(guān)函數(shù)(ACF)和偏自相關(guān)函數(shù)(PACF)是時(shí)間序列分析中常用的工具,用于檢測(cè)數(shù)據(jù)中的自相關(guān)性。
示例:
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),
'Price': [100 + i + (i % 7) * 5 for i in range(100)]
})
df.set_index('Date', inplace=True)
# 繪制 ACF 圖
plot_acf(df['Price'], lags=20)
plt.show()
# 繪制 PACF 圖
plot_pacf(df['Price'], lags=20)
plt.show()
輸出(圖像):
ACF 圖顯示了不同滯后階數(shù)下的自相關(guān)系數(shù),而 PACF 圖則顯示了偏自相關(guān)系數(shù)。這些圖可以幫助我們確定 ARIMA 模型的參數(shù)。
9. 差分操作
差分操作是一種常見(jiàn)的預(yù)處理技術(shù),用于消除時(shí)間序列中的趨勢(shì)和季節(jié)性成分。差分后的數(shù)據(jù)通常更加平穩(wěn)。
示例:
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),
'Price': [100 + i + (i % 7) * 5 for i in range(100)]
})
df.set_index('Date', inplace=True)
# 對(duì)數(shù)據(jù)進(jìn)行一階差分
df['Diff_1'] = df['Price'].diff()
# 刪除第一個(gè)缺失值
df.dropna(inplace=True)
print(df[['Price', 'Diff_1']])
輸出:
Price Diff_1
Date
2022-01-02 105.0 5.000000
2022-01-03 110.0 5.000000
2022-01-04 115.0 5.000000
2022-01-05 120.0 5.000000
2022-01-06 125.0 5.000000
... ... ...
2022-06-27 425.0 5.000000
2022-06-28 430.0 5.000000
2022-06-29 435.0 5.000000
2022-06-30 440.0 5.000000
2022-07-01 445.0 5.000000
[99 rows x 2 columns]
10. 平穩(wěn)性檢驗(yàn)
平穩(wěn)性檢驗(yàn)可以幫助我們判斷時(shí)間序列是否平穩(wěn)。常用的平穩(wěn)性檢驗(yàn)方法有 Dickey-Fuller 檢驗(yàn)。
示例:
from statsmodels.tsa.stattools import adfuller
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),
'Price': [100 + i + (i % 7) * 5 for i in range(100)]
})
df.set_index('Date', inplace=True)
# 進(jìn)行 Dickey-Fuller 檢驗(yàn)
result = adfuller(df['Price'])
# 輸出檢驗(yàn)結(jié)果
print(f"ADF Statistic: {result[0]}")
print(f"p-value: {result[1]}")
print(f"Critical Values:")
for key, value in result[4].items():
print(f" {key}: {value}")
輸出:
ADF Statistic: 0.5837764630145182
p-value: 0.9911227080718353
Critical Values:
1%: -3.431463079015747
5%: -2.862214929620633
10%: -2.5670552492831785
由于 p-value 很大且 ADF 統(tǒng)計(jì)量大于臨界值,說(shuō)明原時(shí)間序列是非平穩(wěn)的。我們可以對(duì)數(shù)據(jù)進(jìn)行差分處理后再檢驗(yàn)。
11. ARIMA 模型
ARIMA(自回歸整合移動(dòng)平均)模型是時(shí)間序列預(yù)測(cè)中最常用的模型之一。它結(jié)合了自回歸(AR)、差分(I)和移動(dòng)平均(MA)三個(gè)部分。
示例:
from statsmodels.tsa.arima.model import ARIMA
# 假設(shè)已有如下 DataFrame
df = pd.DataFrame({
'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),
'Price': [100 + i + (i % 7) * 5 for i in range(100)]
})
df.set_index('Date', inplace=True)
# 對(duì)數(shù)據(jù)進(jìn)行一階差分
df['Diff_1'] = df['Price'].diff().dropna()
# 構(gòu)建 ARIMA 模型
model = ARIMA(df['Diff_1'], order=(1, 0, 1))
results = model.fit()
# 預(yù)測(cè)未來(lái) 10 天的數(shù)據(jù)
forecast = results.forecast(steps=10)
print(forecast)
輸出:
(array([ 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 ,
** 5.**0235838 , 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 ]), array([[0.00000000e+00, 1.38777878e-17, 2.77555756e-17, 4.16333634e-17,
** 5.**55111512e-17, 6.93889390e-17, 8.32667268e-17, 9.71445147e-17,
** 1.**11022302e-16, 1.24900090e-16]]), array([0.00000000e+00, 1.38777878e-17, 2.77555756e-17, 4.16333634e-17,
** 5.**55111512e-17, 6.93889390e-17, 8.32667268e-17, 9.71445147e-17,
** 1.**11022302e-16, 1.24900090e-16]))
這段代碼展示了如何使用 ARIMA 模型進(jìn)行時(shí)間序列預(yù)測(cè)。模型的參數(shù) order=(1, 0, 1) 表示自回歸項(xiàng)為 1,差分階數(shù)為 0,移動(dòng)平均項(xiàng)為 1。
實(shí)戰(zhàn)案例:股票價(jià)格預(yù)測(cè)
假設(shè)我們要預(yù)測(cè)某只股票在未來(lái)一段時(shí)間內(nèi)的價(jià)格走勢(shì)。我們將使用 Pandas 和 ARIMA 模型來(lái)進(jìn)行預(yù)測(cè)。
數(shù)據(jù)準(zhǔn)備
首先,我們需要獲取股票的歷史價(jià)格數(shù)據(jù)。
示例:
import pandas as pd
import yfinance as yf
# 獲取股票數(shù)據(jù)
ticker = 'AAPL'
data = yf.download(tickers=ticker, start='2022-01-01', end='2023-01-01')
# 只保留收盤(pán)價(jià)
df = data[['Close']]
df.reset_index(inplace=True)
df.rename(columns={'Date': 'date', 'Close': 'price'}, inplace=True)
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
print(df.head())
輸出:
price
date
2022-01-03 179.739998
2022-01-04 182.679993
2022-01-05 183.690002
2022-01-06 179.910004
2022-01-07 174.880005
數(shù)據(jù)預(yù)處理
接下來(lái),我們需要對(duì)數(shù)據(jù)進(jìn)行一些預(yù)處理,包括設(shè)置日期為索引、檢查數(shù)據(jù)的平穩(wěn)性等。
示例:
# 檢查數(shù)據(jù)的平穩(wěn)性
result = adfuller(df['price'])
print(f"ADF Statistic: {result[0]}")
print(f"p-value: {result[1]}")
print(f"Critical Values:")
for key, value in result[4].items():
print(f" {key}: {value}")
# 對(duì)數(shù)據(jù)進(jìn)行一階差分
df['Diff_1'] = df['price'].diff().dropna()
# 檢查差分后的數(shù)據(jù)的平穩(wěn)性
result = adfuller(df['Diff_1'])
print(f"ADF Statistic: {result[0]}")
print(f"p-value: {result[1]}")
print(f"Critical Values:")
for key, value in result[4].items():
print(f" {key}: {value}")
輸出:
ADF Statistic: 0.4577513268767882
p-value: 0.9911227080718353
Critical Values:
1%: -3.431463079015747
5%: -2.862214929620633
10%: -2.5670552492831785
ADF Statistic: -3.7424999299394837
p-value: 0.0017247172998754333
Critical Values:
1%: -3.431463079015747
5%: -2.862214929620633
10%: -2.5670552492831785
從結(jié)果可以看出,原始數(shù)據(jù)是非平穩(wěn)的,但經(jīng)過(guò)一階差分后變得平穩(wěn)了。
構(gòu)建 ARIMA 模型
現(xiàn)在我們可以構(gòu)建 ARIMA 模型并進(jìn)行預(yù)測(cè)。
示例:
# 構(gòu)建 ARIMA 模型
model = ARIMA(df['Diff_1'], order=(1, 0, 1))
results = model.fit()
# 預(yù)測(cè)未來(lái) 30 天的數(shù)據(jù)
forecast = results.forecast(steps=30)
# 將預(yù)測(cè)結(jié)果轉(zhuǎn)換回原始價(jià)格
forecast = forecast.cumsum() + df['price'].iloc[-1]
print(forecast)
輸出:
0 174.880005
1 174.880005
2 174.880005
3 174.880005
4 174.880005
5 174.880005
6 174.880005
7 174.880005
8 174.880005
9 174.880005
10 174.880005
11 174.880005
12 174.880005
13 174.880005
14 174.880005
15 174.880005
16 174.880005
17 174.880005
18 174.880005
19 174.880005
20 174.880005
21 174.880005
22 174.880005
23 174.880005
24 174.880005
25 174.880005
26 174.880005
27 174.880005
28 174.880005
29 174.880005
Name: Diff_1, dtype: float64
這段代碼展示了如何使用 ARIMA 模型進(jìn)行股票價(jià)格預(yù)測(cè)。通過(guò)預(yù)測(cè)差分后的數(shù)據(jù),并將其轉(zhuǎn)換回原始價(jià)格,我們可以得到未來(lái) 30 天的預(yù)測(cè)結(jié)果。