大家好!今天我们来聊聊如何用 Pandas 库进行时间序列分析。Pandas 是 Python 中最强大的数据处理库之一,非常适合处理时间序列数据。这篇文章将带你逐步了解时间序列分析的基础知识,以及如何用 Pandas 实现。
1. 时间序列数据简介
时间序列数据是指按照时间顺序排列的数据。比如股票价格、气温变化等。时间序列分析可以帮助我们发现数据中的模式、趋势和周期性变化。
示例:
import pandas as pd
# 创建一个简单的 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. 设置日期为索引
为了方便处理时间序列数据,通常会把日期设置为 DataFrame 的索引。
示例:
# 假设已有如下 DataFrame
df = pd.DataFrame({
'Date': ['2022-01-01', '2022-01-02', '2022-01-03'],
'Price': [100, 105, 110]
})
# 将 'Date' 列转换为 datetime 类型
df['Date'] = pd.to_datetime(df['Date'])
# 将 'Date' 设为索引
df.set_index('Date', inplace=True)
print(df)
输出:
Price
Date
2022-01-01 100
2022-01-02 105
2022-01-03 110
3. 数据重采样
数据重采样是指将时间序列数据重新调整到不同的时间频率。例如,将日数据转换为月数据或年数据。
示例:
# 假设已有如下 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)
# 按月重采样并计算平均值
monthly_df = df.resample('M').mean()
print(monthly_df)
输出:
Price
Date
2022-01-31 122.5
2022-02-28 140.0
4. 插值方法
当时间序列数据中有缺失值时,可以使用插值方法填补这些缺失值。Pandas 提供了多种插值方法。
示例:
# 假设已有如下 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)
# 使用线性插值填补缺失值
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. 移动平均
移动平均是时间序列分析中常用的方法,可以用来平滑数据、发现趋势。
示例:
# 假设已有如下 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)
# 计算 5 日移动平均
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. 季节性分解
季节性分解可以帮助我们识别数据中的趋势、季节性和随机成分。
示例:
from statsmodels.tsa.seasonal import seasonal_decompose
# 假设已有如下 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)
# 进行季节性分解
result = seasonal_decompose(df['Price'], model='additive')
# 查看分解结果
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. 时间序列滞后
滞后是指将时间序列数据向后移动一定的步长。这在构建时间序列模型时非常有用。
示例:
# 假设已有如下 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)
# 计算滞后 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. 自相关和偏自相关函数
自相关函数(ACF)和偏自相关函数(PACF)是时间序列分析中常用的工具,用于检测数据中的自相关性。
示例:
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 假设已有如下 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 图显示了不同滞后阶数下的自相关系数,而 PACF 图则显示了偏自相关系数。这些图可以帮助我们确定 ARIMA 模型的参数。
9. 差分操作
差分操作是一种常见的预处理技术,用于消除时间序列中的趋势和季节性成分。差分后的数据通常更加平稳。
示例:
# 假设已有如下 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)
# 对数据进行一阶差分
df['Diff_1'] = df['Price'].diff()
# 删除第一个缺失值
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. 平稳性检验
平稳性检验可以帮助我们判断时间序列是否平稳。常用的平稳性检验方法有 Dickey-Fuller 检验。
示例:
from statsmodels.tsa.stattools import adfuller
# 假设已有如下 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)
# 进行 Dickey-Fuller 检验
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}")
输出:
ADF Statistic: 0.5837764630145182
p-value: 0.9911227080718353
Critical Values:
1%: -3.431463079015747
5%: -2.862214929620633
10%: -2.5670552492831785
由于 p-value 很大且 ADF 统计量大于临界值,说明原时间序列是非平稳的。我们可以对数据进行差分处理后再检验。
11. ARIMA 模型
ARIMA(自回归整合移动平均)模型是时间序列预测中最常用的模型之一。它结合了自回归(AR)、差分(I)和移动平均(MA)三个部分。
示例:
from statsmodels.tsa.arima.model import ARIMA
# 假设已有如下 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)
# 对数据进行一阶差分
df['Diff_1'] = df['Price'].diff().dropna()
# 构建 ARIMA 模型
model = ARIMA(df['Diff_1'], order=(1, 0, 1))
results = model.fit()
# 预测未来 10 天的数据
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 模型进行时间序列预测。模型的参数 order=(1, 0, 1) 表示自回归项为 1,差分阶数为 0,移动平均项为 1。
实战案例:股票价格预测
假设我们要预测某只股票在未来一段时间内的价格走势。我们将使用 Pandas 和 ARIMA 模型来进行预测。
数据准备
首先,我们需要获取股票的历史价格数据。
示例:
import pandas as pd
import yfinance as yf
# 获取股票数据
ticker = 'AAPL'
data = yf.download(tickers=ticker, start='2022-01-01', end='2023-01-01')
# 只保留收盘价
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
数据预处理
接下来,我们需要对数据进行一些预处理,包括设置日期为索引、检查数据的平稳性等。
示例:
# 检查数据的平稳性
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}")
# 对数据进行一阶差分
df['Diff_1'] = df['price'].diff().dropna()
# 检查差分后的数据的平稳性
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
从结果可以看出,原始数据是非平稳的,但经过一阶差分后变得平稳了。
构建 ARIMA 模型
现在我们可以构建 ARIMA 模型并进行预测。
示例:
# 构建 ARIMA 模型
model = ARIMA(df['Diff_1'], order=(1, 0, 1))
results = model.fit()
# 预测未来 30 天的数据
forecast = results.forecast(steps=30)
# 将预测结果转换回原始价格
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 模型进行股票价格预测。通过预测差分后的数据,并将其转换回原始价格,我们可以得到未来 30 天的预测结果。