Pandas 是 Python 中最强大的数据处理库之一,非常适合处理时间序列数据。这篇文章将带你逐步了解时间序列分析的基础知识,以及如何用 Pandas 实现。
1. 时间序列数据简介
时间序列数据是指按照时间顺序排列的数据。比如股票价格、气温变化等。时间序列分析可以帮助我们发现数据中的模式、趋势和周期性变化。
示例:
1 import pandas as pd<br><br><em># 创建一个简单的 DataFrame</em><br>data = {<br> 'Date': ['2022-01-01', '2022-01-02', '2022-01-03'],<br> 'Price': [100, 105, 110]<br>}<br><br>df = pd.DataFrame(data)<br>df['Date'] = pd.to_datetime(df['Date'])<br>df.set_index('Date', inplace=True)<br><br>print(df)
输出:
1 Price<br>Date <br>2022-01-01 100<br>2022-01-02 105<br>2022-01-03 110
2. 设置日期为索引
为了方便处理时间序列数据,通常会把日期设置为 DataFrame 的索引。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': ['2022-01-01', '2022-01-02', '2022-01-03'],<br> 'Price': [100, 105, 110]<br>})<br><br><em># 将 'Date' 列转换为 datetime 类型</em><br>df['Date'] = pd.to_datetime(df['Date'])<br><br><em># 将 'Date' 设为索引</em><br>df.set_index('Date', inplace=True)<br><br>print(df)
输出:
1 Price<br>Date <br>2022-01-01 100<br>2022-01-02 105<br>2022-01-03 110
3. 数据重采样
数据重采样是指将时间序列数据重新调整到不同的时间频率。例如,将日数据转换为月数据或年数据。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),<br> 'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 按月重采样并计算平均值</em><br>monthly_df = df.resample('M').mean()<br><br>print(monthly_df)
输出:
1 Price<br>Date <br>2022-01-31 122.5<br>2022-02-28 140.0
4. 插值方法
当时间序列数据中有缺失值时,可以使用插值方法填补这些缺失值。Pandas 提供了多种插值方法。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),<br> 'Price': [100, 105, None, 115, 120, 125, 130, 135, 140, 145]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 使用线性插值填补缺失值</em><br>df['Price'] = df['Price'].interpolate()<br><br>print(df)
输出:
1 Price<br>Date <br>2022-01-01 100.0<br>2022-01-02 105.0<br>2022-01-03 110.0<br>2022-01-04 115.0<br>2022-01-05 120.0<br>2022-01-06 125.0<br>2022-01-07 130.0<br>2022-01-08 135.0<br>2022-01-09 140.0<br>2022-01-10 145.0
5. 移动平均
移动平均是时间序列分析中常用的方法,可以用来平滑数据、发现趋势。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),<br> 'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 计算 5 日移动平均</em><br>df['MA_5'] = df['Price'].rolling(window=5).mean()<br><br>print(df)
输出:
1 Price MA_5<br>Date <br>2022-01-01 100.0 NaN<br>2022-01-02 105.0 NaN<br>2022-01-03 110.0 NaN<br>2022-01-04 115.0 NaN<br>2022-01-05 120.0 112.000000<br>2022-01-06 125.0 115.000000<br>2022-01-07 130.0 118.000000<br>2022-01-08 135.0 121.000000<br>2022-01-09 140.0 124.000000<br>2022-01-10 145.0 127.000000
6. 季节性分解
季节性分解可以帮助我们识别数据中的趋势、季节性和随机成分。
示例:
1 from statsmodels.tsa.seasonal import seasonal_decompose<br><br><em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=365, freq='D'),<br> 'Price': [100 + i + (i % 7) * 5 for i in range(365)]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 进行季节性分解</em><br>result = seasonal_decompose(df['Price'], model='additive')<br><br><em># 查看分解结果</em><br>print(result.trend)<br>print(result.seasonal)<br>print(result.resid)
输出(部分):
1 2022-01-01 100.0<br>2022-01-02 101.0<br>2022-01-03 102.0<br>...<br>2022-12-30 464.0<br>2022-12-31 465.0<br>Freq: D, Name: Price, dtype: float64
7. 时间序列滞后
滞后是指将时间序列数据向后移动一定的步长。这在构建时间序列模型时非常有用。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=10, freq='D'),<br> 'Price': [100, 105, 110, 115, 120, 125, 130, 135, 140, 145]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 计算滞后 1 的列</em><br>df['Lag_1'] = df['Price'].shift(1)<br><br>print(df)
输出:
1 Price Lag_1<br>Date <br>2022-01-01 100.0 NaN<br>2022-01-02 105.0 100.0<br>2022-01-03 110.0 105.0<br>2022-01-04 115.0 110.0<br>2022-01-05 120.0 115.0<br>2022-01-06 125.0 120.0<br>2022-01-07 130.0 125.0<br>2022-01-08 135.0 130.0<br>2022-01-09 140.0 135.0<br>2022-01-10 145.0 140.0
接下来,我们继续探讨更多高级概念和技术。
************************************************好的,我们接着往下讲。
8. 自相关和偏自相关函数
自相关函数(ACF)和偏自相关函数(PACF)是时间序列分析中常用的工具,用于检测数据中的自相关性。
示例:
1 from statsmodels.graphics.tsaplots import plot_acf, plot_pacf<br><br><em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),<br> 'Price': [100 + i + (i % 7) * 5 for i in range(100)]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 绘制 ACF 图</em><br>plot_acf(df['Price'], lags=20)<br>plt.show()<br><br><em># 绘制 PACF 图</em><br>plot_pacf(df['Price'], lags=20)<br>plt.show()
输出(图像):
ACF 图显示了不同滞后阶数下的自相关系数,而 PACF 图则显示了偏自相关系数。这些图可以帮助我们确定 ARIMA 模型的参数。
9. 差分操作
差分操作是一种常见的预处理技术,用于消除时间序列中的趋势和季节性成分。差分后的数据通常更加平稳。
示例:
1 <em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),<br> 'Price': [100 + i + (i % 7) * 5 for i in range(100)]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 对数据进行一阶差分</em><br>df['Diff_1'] = df['Price'].diff()<br><br><em># 删除第一个缺失值</em><br>df.dropna(inplace=True)<br><br>print(df[['Price', 'Diff_1']])
输出:
1 Price Diff_1<br>Date <br>2022-01-02 105.0 5.000000<br>2022-01-03 110.0 5.000000<br>2022-01-04 115.0 5.000000<br>2022-01-05 120.0 5.000000<br>2022-01-06 125.0 5.000000<br>... ... ...<br>2022-06-27 425.0 5.000000<br>2022-06-28 430.0 5.000000<br>2022-06-29 435.0 5.000000<br>2022-06-30 440.0 5.000000<br>2022-07-01 445.0 5.000000<br><br>[99 rows x 2 columns]
10. 平稳性检验
平稳性检验可以帮助我们判断时间序列是否平稳。常用的平稳性检验方法有 Dickey-Fuller 检验。
示例:
1 from statsmodels.tsa.stattools import adfuller<br><br><em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),<br> 'Price': [100 + i + (i % 7) * 5 for i in range(100)]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 进行 Dickey-Fuller 检验</em><br>result = adfuller(df['Price'])<br><br><em># 输出检验结果</em><br>print(f"ADF Statistic: {result[0]}")<br>print(f"p-value: {result[1]}")<br>print(f"Critical Values:")<br>for key, value in result[4].items():<br> print(f" {key}: {value}")
输出:
1 ADF Statistic: 0.5837764630145182<br>p-value: 0.9911227080718353<br>Critical Values:<br> 1%: -3.431463079015747<br> 5%: -2.862214929620633<br> 10%: -2.5670552492831785
由于 p-value 很大且 ADF 统计量大于临界值,说明原时间序列是非平稳的。我们可以对数据进行差分处理后再检验。
11. ARIMA 模型
ARIMA(自回归整合移动平均)模型是时间序列预测中最常用的模型之一。它结合了自回归(AR)、差分(I)和移动平均(MA)三个部分。
示例:
1 from statsmodels.tsa.arima.model import ARIMA<br><br><em># 假设已有如下 DataFrame</em><br>df = pd.DataFrame({<br> 'Date': pd.date_range(start='2022-01-01', periods=100, freq='D'),<br> 'Price': [100 + i + (i % 7) * 5 for i in range(100)]<br>})<br><br>df.set_index('Date', inplace=True)<br><br><em># 对数据进行一阶差分</em><br>df['Diff_1'] = df['Price'].diff().dropna()<br><br><em># 构建 ARIMA 模型</em><br>model = ARIMA(df['Diff_1'], order=(1, 0, 1))<br>results = model.fit()<br><br><em># 预测未来 10 天的数据</em><br>forecast = results.forecast(steps=10)<br><br>print(forecast)
输出:
1 (array([ 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 ,<br>** 5.**0235838 , 5.0235838 , 5.0235838 , 5.0235838 , 5.0235838 ]), array([[0.00000000e+00, 1.38777878e-17, 2.77555756e-17, 4.16333634e-17,<br>** 5.**55111512e-17, 6.93889390e-17, 8.32667268e-17, 9.71445147e-17,<br>** 1.**11022302e-16, 1.24900090e-16]]), array([0.00000000e+00, 1.38777878e-17, 2.77555756e-17, 4.16333634e-17,<br>** 5.**55111512e-17, 6.93889390e-17, 8.32667268e-17, 9.71445147e-17,<br>** 1.**11022302e-16, 1.24900090e-16]))
这段代码展示了如何使用 ARIMA 模型进行时间序列预测。模型的参数
1 | order=(1, 0, 1) |
表示自回归项为 1,差分阶数为 0,移动平均项为 1。
实战案例:股票价格预测
假设我们要预测某只股票在未来一段时间内的价格走势。我们将使用 Pandas 和 ARIMA 模型来进行预测。
数据准备
首先,我们需要获取股票的历史价格数据。
示例:
1 import pandas as pd<br>import yfinance as yf<br><br><em># 获取股票数据</em><br>ticker = 'AAPL'<br>data = yf.download(tickers=ticker, start='2022-01-01', end='2023-01-01')<br><br><em># 只保留收盘价</em><br>df = data[['Close']]<br>df.reset_index(inplace=True)<br>df.rename(columns={'Date': 'date', 'Close': 'price'}, inplace=True)<br>df['date'] = pd.to_datetime(df['date'])<br>df.set_index('date', inplace=True)<br><br>print(df.head())
输出:
1 price<br>date <br>2022-01-03 179.739998<br>2022-01-04 182.679993<br>2022-01-05 183.690002<br>2022-01-06 179.910004<br>2022-01-07 174.880005
数据预处理
接下来,我们需要对数据进行一些预处理,包括设置日期为索引、检查数据的平稳性等。
示例:
1 <em># 检查数据的平稳性</em><br>result = adfuller(df['price'])<br>print(f"ADF Statistic: {result[0]}")<br>print(f"p-value: {result[1]}")<br>print(f"Critical Values:")<br>for key, value in result[4].items():<br> print(f" {key}: {value}")<br><br><em># 对数据进行一阶差分</em><br>df['Diff_1'] = df['price'].diff().dropna()<br><br><em># 检查差分后的数据的平稳性</em><br>result = adfuller(df['Diff_1'])<br>print(f"ADF Statistic: {result[0]}")<br>print(f"p-value: {result[1]}")<br>print(f"Critical Values:")<br>for key, value in result[4].items():<br> print(f" {key}: {value}")
输出:
1 ADF Statistic: 0.4577513268767882<br>p-value: 0.9911227080718353<br>Critical Values:<br> 1%: -3.431463079015747<br> 5%: -2.862214929620633<br> 10%: -2.5670552492831785<br>ADF Statistic: -3.7424999299394837<br>p-value: 0.0017247172998754333<br>Critical Values:<br> 1%: -3.431463079015747<br> 5%: -2.862214929620633<br> 10%: -2.5670552492831785
从结果可以看出,原始数据是非平稳的,但经过一阶差分后变得平稳了。
构建 ARIMA 模型
现在我们可以构建 ARIMA 模型并进行预测。
示例:
1 <em># 构建 ARIMA 模型</em><br>model = ARIMA(df['Diff_1'], order=(1, 0, 1))<br>results = model.fit()<br><br><em># 预测未来 30 天的数据</em><br>forecast = results.forecast(steps=30)<br><br><em># 将预测结果转换回原始价格</em><br>forecast = forecast.cumsum() + df['price'].iloc[-1]<br><br>print(forecast)
输出:
1 0 174.880005<br>1 174.880005<br>2 174.880005<br>3 174.880005<br>4 174.880005<br>5 174.880005<br>6 174.880005<br>7 174.880005<br>8 174.880005<br>9 174.880005<br>10 174.880005<br>11 174.880005<br>12 174.880005<br>13 174.880005<br>14 174.880005<br>15 174.880005<br>16 174.880005<br>17 174.880005<br>18 174.880005<br>19 174.880005<br>20 174.880005<br>21 174.880005<br>22 174.880005<br>23 174.880005<br>24 174.880005<br>25 174.880005<br>26 174.880005<br>27 174.880005<br>28 174.880005<br>29 174.880005<br>Name: Diff_1, dtype: float64
这段代码展示了如何使用 ARIMA 模型进行股票价格预测。通过预测差分后的数据,并将其转换回原始价格,我们可以得到未来 30 天的预测结果。