时间序列检验 (TimeSeriesTests)
时间序列检验类提供了8种专门用于时间序列数据分析的统计检验方法。这些检验在经济学、金融学、工程学等时间序列分析中具有重要作用。
- class TimeSeriesTests
时间序列检验类,包含平稳性、序列相关性、协整性等多种时间序列特性检验方法。所有方法都返回
TestResult对象。主要方法:
检验方法详解
Augmented Dickey-Fuller检验 (ADF)
- adf_test(data: np.ndarray | List, alpha: float = 0.05, regression: str = 'c', autolag: str = 'AIC') TestResult
Augmented Dickey-Fuller单位根检验,检验时间序列的平稳性。
参数:
data: 时间序列数据
regression: 回归模式(’c’: 含常数项, ‘ct’: 含常数项和趋势, ‘ctt’: 含常数项、趋势和二次趋势, ‘n’: 无常数项)
autolag: 滞后阶数选择方法(’AIC’, ‘BIC’, ‘HQIC’, 或具体数字)
alpha: 显著性水平
适用条件:
时间序列数据
样本量 ≥ 20
数据按时间顺序排列
原假设: 序列存在单位根(非平稳)
应用场景:
检验序列平稳性
回归分析前的预处理
确定差分阶数
示例:
>>> from pywayne.statistics import TimeSeriesTests >>> import numpy as np >>> >>> tst = TimeSeriesTests() >>> # 非平稳序列(随机游走) >>> data = np.cumsum(np.random.normal(0, 1, 100)) >>> result = tst.adf_test(data) >>> print(f"ADF统计量: {result.statistic:.4f}, 平稳性: {result.reject_null}")
KPSS检验
- kpss_test(data: np.ndarray | List, regression: str = 'c', nlags: str = 'auto', alpha: float = 0.05) TestResult
KPSS检验,检验时间序列的平稳性(与ADF检验互补)。
参数:
data: 时间序列数据
regression: 回归模式(’c’: 水平平稳, ‘ct’: 趋势平稳)
nlags: 滞后阶数(’auto’或具体数字)
alpha: 显著性水平
适用条件:
时间序列数据
适用于各种样本量
与ADF检验结合使用
原假设: 序列是平稳的
应用场景:
与ADF检验结合确认平稳性
区分趋势平稳和差分平稳
平稳性的稳健检验
示例:
>>> # 平稳序列(白噪声) >>> stationary_data = np.random.normal(0, 1, 100) >>> result = tst.kpss_test(stationary_data) >>> print(f"KPSS统计量: {result.statistic:.4f}, 平稳性: {not result.reject_null}")
Ljung-Box检验
- ljung_box_test(data: np.ndarray | List, lags: int = 10, alpha: float = 0.05) TestResult
Ljung-Box检验,检验时间序列的序列相关性(自相关)。
参数:
data: 时间序列数据或残差
lags: 检验的滞后阶数
alpha: 显著性水平
适用条件:
时间序列数据
常用于模型残差检验
样本量 > 滞后阶数
原假设: 序列无自相关(独立)
应用场景:
模型残差的独立性检验
ARIMA模型诊断
随机性检验
示例:
>>> # 有自相关的序列 >>> ar_data = np.zeros(100) >>> ar_data[0] = np.random.normal() >>> for i in range(1, 100): ... ar_data[i] = 0.7 * ar_data[i-1] + np.random.normal(0, 0.5) >>> result = tst.ljung_box_test(ar_data, lags=10) >>> print(f"存在自相关: {result.reject_null}")
游程检验
- runs_test(data: np.ndarray | List, alpha: float = 0.05) TestResult
游程检验,检验序列的随机性。
参数:
data: 时间序列数据
alpha: 显著性水平
适用条件:
二分类或可二分类的数据
样本量 ≥ 20
用于检验随机性
原假设: 序列是随机的
应用场景:
检验序列随机性
质量控制中的模式检验
预测模型残差分析
示例:
>>> # 周期性模式数据 >>> pattern_data = np.tile([1, -1], 50) # 交替模式 >>> result = tst.runs_test(pattern_data) >>> print(f"随机性: {not result.reject_null}")
ARCH效应检验
- arch_test(data: np.ndarray | List, lags: int = 1, alpha: float = 0.05) TestResult
ARCH效应检验,检验时间序列的条件异方差性。
参数:
data: 时间序列数据或残差
lags: 滞后阶数
alpha: 显著性水平
适用条件:
时间序列数据
常用于金融数据
样本量 > 滞后阶数
原假设: 无ARCH效应(同方差)
应用场景:
金融时间序列分析
波动率建模前的检验
GARCH模型的必要性判断
示例:
>>> # 模拟ARCH效应数据 >>> arch_data = np.random.normal(0, 1, 100) >>> for i in range(1, 100): ... vol = 0.1 + 0.8 * arch_data[i-1]**2 ... arch_data[i] = np.random.normal(0, np.sqrt(vol)) >>> result = tst.arch_test(arch_data) >>> print(f"存在ARCH效应: {result.reject_null}")
Granger因果检验
- granger_causality(data1: np.ndarray | List, data2: np.ndarray | List, max_lag: int = 4, alpha: float = 0.05) TestResult
Granger因果检验,检验一个时间序列是否有助于预测另一个序列。
参数:
data1: 第一个时间序列
data2: 第二个时间序列
max_lag: 最大滞后阶数
alpha: 显著性水平
适用条件:
两个时间序列
序列应为平稳的
样本量 > 滞后阶数
原假设: 第一个序列不Granger因果于第二个序列
应用场景:
经济变量间的因果关系分析
金融市场传导机制研究
政策效果评估
示例:
>>> # 创建因果关系数据 >>> x = np.random.normal(0, 1, 100) >>> y = np.zeros(100) >>> y[0] = np.random.normal() >>> for i in range(1, 100): ... y[i] = 0.5 * x[i-1] + 0.3 * y[i-1] + np.random.normal(0, 0.5) >>> data = np.column_stack([x, y]) >>> result = tst.granger_causality(data[:, 0], data[:, 1]) >>> print(f"存在Granger因果关系: {result.reject_null}")
Engle-Granger协整检验
- engle_granger_cointegration(data1: np.ndarray | List, data2: np.ndarray | List, alpha: float = 0.05) TestResult
Engle-Granger协整检验,检验两个非平稳序列间的长期均衡关系。
参数:
data1: 第一个时间序列
data2: 第二个时间序列
alpha: 显著性水平
适用条件:
两个序列均为I(1)非平稳序列
序列长度相等
样本量 ≥ 50
原假设: 两序列不存在协整关系
应用场景:
经济变量间长期关系分析
金融资产间的均值回复关系
配对交易策略验证
示例:
>>> # 协整序列示例 >>> t = np.arange(100) >>> trend = 0.05 * t >>> y1 = trend + np.cumsum(np.random.normal(0, 1, 100)) >>> y2 = 2 * trend + y1 + np.random.normal(0, 0.5, 100) >>> result = tst.engle_granger_cointegration(y1, y2) >>> print(f"存在协整关系: {result.reject_null}")
Breusch-Godfrey检验
- breusch_godfrey_test(residuals: np.ndarray | List, lags: int = 1, alpha: float = 0.05) TestResult
Breusch-Godfrey检验,检验回归残差的序列相关性。
参数:
residuals: 回归残差
lags: 检验的滞后阶数
alpha: 显著性水平
适用条件:
时间序列回归的残差
适用于各种回归模型
样本量 > 滞后阶数
原假设: 残差无序列相关
应用场景:
时间序列回归诊断
模型设定检验
ARIMA模型残差分析
示例:
>>> # 有序列相关的残差 >>> residuals = np.zeros(100) >>> for i in range(1, 100): ... residuals[i] = 0.6 * residuals[i-1] + np.random.normal(0, 1) >>> result = tst.breusch_godfrey_test(residuals) >>> print(f"残差存在序列相关: {result.reject_null}")
使用建议
平稳性检验策略
单位根检验流程:
Step 1: 使用ADF检验(原假设:非平稳)
Step 2: 使用KPSS检验(原假设:平稳)
Step 3: 结合两个检验结果判断
结果解释:
ADF拒绝 + KPSS不拒绝: 平稳序列
ADF不拒绝 + KPSS拒绝: 非平稳序列
都拒绝: 需要进一步分析或变换
都不拒绝: 结果不确定,需要更多证据
差分处理:
一阶差分后重新检验
注意过度差分问题
考虑季节性差分
序列相关性检验
Ljung-Box检验应用:
选择适当的滞后阶数(通常为样本量的1/4)
结合ACF/PACF图形分析
用于模型诊断和残差检验
游程检验补充:
检验序列的随机性
适用于二分类或符号序列
可以检测周期性模式
协整关系分析
协整检验前提:
确认变量的积分阶数相同(通常为I(1))
变量数量不宜过多(Engle-Granger适用于两变量)
样本量要足够大
结果应用:
建立误差修正模型(ECM)
长期均衡关系分析
短期动态调整机制研究
ARCH效应分析
检验时机:
在建立均值方程后
检验残差的条件异方差
确定是否需要GARCH建模
后续处理:
建立GARCH族模型
考虑结构突变
使用稳健标准误
典型应用示例
时间序列平稳性分析
from pywayne.statistics import TimeSeriesTests
import numpy as np
import matplotlib.pyplot as plt
# 生成不同类型的时间序列
np.random.seed(42)
n = 200
# 1. 平稳序列(AR(1))
stationary = np.zeros(n)
for i in range(1, n):
stationary[i] = 0.7 * stationary[i-1] + np.random.normal(0, 1)
# 2. 非平稳序列(随机游走)
non_stationary = np.cumsum(np.random.normal(0, 1, n))
# 3. 趋势序列
trend_series = 0.05 * np.arange(n) + np.random.normal(0, 1, n)
tst = TimeSeriesTests()
series_data = [
("平稳序列", stationary),
("随机游走", non_stationary),
("趋势序列", trend_series)
]
print("时间序列平稳性检验结果:")
print("=" * 60)
for name, data in series_data:
print(f"\n{name}:")
# ADF检验
adf_result = tst.adf_test(data)
print(f" ADF检验: 统计量={adf_result.statistic:.4f}, "
f"p值={adf_result.p_value:.4f}, 拒绝原假设={adf_result.reject_null}")
# KPSS检验
kpss_result = tst.kpss_test(data)
print(f" KPSS检验: 统计量={kpss_result.statistic:.4f}, "
f"p值={kpss_result.p_value:.4f}, 拒绝原假设={kpss_result.reject_null}")
# 平稳性结论
if adf_result.reject_null and not kpss_result.reject_null:
conclusion = "平稳"
elif not adf_result.reject_null and kpss_result.reject_null:
conclusion = "非平稳"
else:
conclusion = "需要进一步分析"
print(f" 结论: {conclusion}")
ARIMA模型诊断
from statsmodels.tsa.arima.model import ARIMA
import numpy as np
# 生成ARIMA(1,1,1)数据
np.random.seed(42)
n = 200
# 模拟非平稳序列
data = np.cumsum(np.random.normal(0, 1, n))
for i in range(1, n):
data[i] += 0.3 * (data[i-1] - data[i-2]) if i > 1 else 0
# 拟合ARIMA模型
model = ARIMA(data, order=(1, 1, 1))
fitted_model = model.fit()
# 获取残差
residuals = fitted_model.resid
tst = TimeSeriesTests()
print("ARIMA模型残差诊断:")
print("=" * 40)
# Ljung-Box检验
lb_result = tst.ljung_box_test(residuals, lags=10)
print(f"Ljung-Box检验: p值={lb_result.p_value:.4f}, "
f"残差独立={not lb_result.reject_null}")
# ARCH效应检验
arch_result = tst.arch_test(residuals)
print(f"ARCH效应检验: p值={arch_result.p_value:.4f}, "
f"同方差={not arch_result.reject_null}")
# 游程检验
runs_result = tst.runs_test(residuals)
print(f"游程检验: p值={runs_result.p_value:.4f}, "
f"随机性={not runs_result.reject_null}")
# 模型诊断结论
if not lb_result.reject_null and not arch_result.reject_null and not runs_result.reject_null:
print("\n结论: 模型残差表现良好,模型设定合理")
else:
print("\n结论: 模型可能存在设定问题,需要调整")
金融时间序列分析
# 模拟股票价格和收益率数据
np.random.seed(42)
n = 300
# 股票价格(几何布朗运动)
returns = np.random.normal(0.001, 0.02, n) # 日收益率
prices = 100 * np.exp(np.cumsum(returns)) # 价格序列
# 引入波动率聚集效应
vol_returns = np.zeros(n)
vol_returns[0] = returns[0]
for i in range(1, n):
vol = 0.02 * (1 + 0.8 * vol_returns[i-1]**2) # GARCH效应
vol_returns[i] = np.random.normal(0, vol)
tst = TimeSeriesTests()
print("金融时间序列分析:")
print("=" * 40)
# 价格序列平稳性
print("1. 价格序列分析:")
price_adf = tst.adf_test(prices)
print(f" ADF检验: p值={price_adf.p_value:.4f}, 平稳={price_adf.reject_null}")
# 收益率序列平稳性
print("\n2. 收益率序列分析:")
return_adf = tst.adf_test(returns)
print(f" ADF检验: p值={return_adf.p_value:.4f}, 平稳={return_adf.reject_null}")
# 收益率序列的ARCH效应
arch_result = tst.arch_test(vol_returns, lags=5)
print(f" ARCH效应: p值={arch_result.p_value:.4f}, 存在={arch_result.reject_null}")
# 序列相关性
lb_result = tst.ljung_box_test(vol_returns, lags=10)
print(f" 序列相关: p值={lb_result.p_value:.4f}, 存在={lb_result.reject_null}")
print("\n结论:")
print(f" 价格序列: {'平稳' if price_adf.reject_null else '非平稳'}")
print(f" 收益率序列: {'平稳' if return_adf.reject_null else '非平稳'}")
print(f" 波动率聚集: {'存在' if arch_result.reject_null else '不存在'}")
协整关系分析
# 模拟协整的经济变量
np.random.seed(42)
n = 200
# 生成两个协整序列
# 假设是消费和收入的长期关系
common_trend = np.cumsum(np.random.normal(0, 1, n)) # 共同趋势
income = common_trend + np.random.normal(0, 0.5, n)
consumption = 0.8 * income + np.random.normal(0, 0.3, n)
# 生成非协整序列作为对比
gdp = np.cumsum(np.random.normal(0, 1, n))
unemployment = np.cumsum(np.random.normal(0, 1, n))
tst = TimeSeriesTests()
print("协整关系分析:")
print("=" * 40)
# 检验变量的单整性
print("1. 单位根检验:")
variables = [income, consumption, gdp, unemployment]
var_names = ['收入', '消费', 'GDP', '失业率']
for name, var in zip(var_names, variables):
adf_result = tst.adf_test(var)
print(f" {name}: ADF统计量={adf_result.statistic:.4f}, "
f"p值={adf_result.p_value:.4f}, I(1)={not adf_result.reject_null}")
# 协整检验
print("\n2. 协整检验:")
# 理论上协整的变量对
cointegration_result1 = tst.engle_granger_cointegration(income, consumption)
print(f" 收入-消费: 统计量={cointegration_result1.statistic:.4f}, "
f"p值={cointegration_result1.p_value:.4f}, 协整={cointegration_result1.reject_null}")
# 理论上非协整的变量对
cointegration_result2 = tst.engle_granger_cointegration(gdp, unemployment)
print(f" GDP-失业率: 统计量={cointegration_result2.statistic:.4f}, "
f"p值={cointegration_result2.p_value:.4f}, 协整={cointegration_result2.reject_null}")
print("\n结论:")
if cointegration_result1.reject_null:
print(" 收入和消费存在长期均衡关系,可以建立误差修正模型")
if not cointegration_result2.reject_null:
print(" GDP和失业率不存在协整关系,需要分别建模")
Granger因果关系分析
# 模拟具有因果关系的经济变量
np.random.seed(42)
n = 150
# 生成Granger因果关系:货币供应量 → 通胀率
money_supply = np.random.normal(0, 1, n)
inflation = np.zeros(n)
for i in range(2, n):
# 通胀率受过去货币供应量影响
inflation[i] = (0.4 * money_supply[i-1] + 0.3 * money_supply[i-2] +
0.2 * inflation[i-1] + np.random.normal(0, 0.5))
# 构建多变量时间序列
data = np.column_stack([money_supply[2:], inflation[2:]])
tst = TimeSeriesTests()
print("Granger因果关系分析:")
print("=" * 40)
# 检验平稳性(Granger因果检验要求平稳序列)
print("1. 平稳性检验:")
for i, name in enumerate(['货币供应量', '通胀率']):
adf_result = tst.adf_test(data[:, i])
print(f" {name}: ADF p值={adf_result.p_value:.4f}, 平稳={adf_result.reject_null}")
# Granger因果检验
print("\n2. Granger因果检验:")
# 货币供应量 → 通胀率
granger_result = tst.granger_causality(data[:, 0], data[:, 1])
print(f" 货币供应量 → 通胀率: F统计量={granger_result.statistic:.4f}, "
f"p值={granger_result.p_value:.4f}, 因果关系={granger_result.reject_null}")
# 反向检验:通胀率 → 货币供应量
data_reversed = np.column_stack([data[:, 1], data[:, 0]])
granger_result_rev = tst.granger_causality(data_reversed[:, 0], data_reversed[:, 1])
print(f" 通胀率 → 货币供应量: F统计量={granger_result_rev.statistic:.4f}, "
f"p值={granger_result_rev.p_value:.4f}, 因果关系={granger_result_rev.reject_null}")
print("\n结论:")
if granger_result.reject_null and not granger_result_rev.reject_null:
print(" 存在单向因果关系:货币供应量Granger因果于通胀率")
elif granger_result.reject_null and granger_result_rev.reject_null:
print(" 存在双向因果关系")
else:
print(" 不存在显著的Granger因果关系")
注意事项
数据预处理: - 确保数据按时间顺序排列 - 处理缺失值和异常值 - 考虑季节性调整
样本量要求: - 大多数检验需要足够的样本量 - 滞后阶数不宜过大相对于样本量 - 考虑样本量对检验功效的影响
模型设定: - 选择适当的趋势项和常数项 - 滞后阶数的选择很重要 - 结合经济理论和数据特征
结果解释: - 平稳性检验需要结合多种方法 - 因果关系不等于真实因果 - 协整关系表示长期均衡而非短期关系