关于迪基-富勒检验

量化交易概念
Author

王一刀

Published

August 20, 2024

时间序列模型

时间序列模型是一种用于分析和预测时间序列数据的统计模型。这些模型通过识别数据中的趋势、季节性和其他模式,来预测未来的值。以下是关于时间序列模型的相关信息:

时间序列模型的定义

时间序列模型定义为一个随机过程,即按时间排序的随机变量的集合。每个时刻的位置点作为一个随机变量,其取值是从一个分布中采样得到的。

时间序列模型的分类

  • 自回归模型 (AR):根据历史观测值来预测未来时序。
  • 移动平均模型 (MA):根据白噪声的系数加权和来预测未来时序。
  • 自回归移动平均模型 (ARMA):结合了AR和MA的特点,同时考虑历史观测值和白噪声的影响。
  • 差分移动自回归模型 (ARIMA):适用于有明显上升或下降趋势的数据集,通过差分使数据平稳后使用ARMA拟合。

时间序列模型的平稳性

平稳性是指时间序列的统计特性(如均值、方差和自协方差)不随时间变化。如果时间序列有季节性和趋势性,则视为不平稳。平稳性是许多时间序列预测模型(如自回归模型)的基础。

特征根与时间序列模型的关系

特征根是判断时间序列模型平稳性的关键。一个平稳时间序列模型的特征根都在单位圆内,这意味着模型是稳定的,能够提供可靠的预测。

特征根

特征根是线性代数中的一个重要概念,特别是在时间序列分析中。特征根与特征向量一起,构成了理解线性变换和动态系统行为的基础。以下是关于特征根的相关信息:

特征根的定义

特征根是线性代数中一个矩阵的特征方程的根,它表示矩阵对应的线性变换在特定方向上的伸缩因子。在时间序列分析中,特征根与时间序列的稳定性密切相关。

特征根在时间序列分析中的应用

  • 平稳性检验:通过检查特征根的位置(是否在单位圆内),可以判断时间序列是否平稳。如果所有特征根都在单位圆内,则时间序列是平稳的,否则是非平稳的。
  • 模型选择:不同的时间序列模型(如AR、MA、ARMA)的特征根有不同的性质,这些性质可以帮助我们选择合适的模型进行分析和预测。

特征根与时间序列稳定性的关系

单位根与序列稳定性:如果一个时间序列的特征根包含单位根(即特征根的绝对值等于1),则该序列是非平稳的。单位根的存在意味着序列的统计特性会随时间变化,这可能会影响到时间序列的预测能力。

特征方程:对于时间序列模型,特征方程是通过将模型的差分方程转化为代数方程得到的。例如,AR(1)模型的特征方程为 1−aZ=0,其中 a 是自回归系数,Z 是特征根

对模型预测能力的影响:特征根的位置决定了时间序列模型的预测能力。平稳的时间序列模型(所有特征根都在单位圆内)可以提供可靠的短期预测,而非平稳序列可能需要通过差分等方法转换为平稳序列后才能进行有效预测。

特征根的理解

特征根是线性代数中的一个重要概念,它与矩阵的特征方程密切相关。特征方程是一个关于未知数λ的方程,这个方程是通过求解矩阵A减去λ倍的单位矩阵后的行列式等于0得到的。

具体来说,对于一个n×n的矩阵A,其特征方程可以表示为: det(A - λI) = 0

其中,det表示行列式,I是n×n的单位矩阵,λ是我们要求的特征根。

这个特征方程的解,即特征根λ,具有特殊的意义。它表示矩阵A对应的线性变换在某个特定方向上的伸缩因子。换句话说,如果我们有一个向量v,它是对应于特征根λ的特征向量,那么矩阵A作用在这个向量上,就相当于把这个向量伸缩了λ倍。

举个例子来说明这个概念:

假设我们有一个2×2的矩阵A:

A = [[3, 1],
     [1, 3]]

我们需要找到这个矩阵的特征根和特征向量。

首先,我们写出特征方程: det(A - λI) = det([[3-λ, 1], [1, 3-λ]]) = (3-λ)^2 - 1 = λ^2 - 6λ + 8 = 0

解这个方程,我们得到两个特征根: λ1 = 2, λ2 = 4

接下来,我们分别求对应于这两个特征根的特征向量。

对于λ1 = 2,我们解方程组(A - 2I)v = 0,得到一个特征向量v1 = [1, -1]^T(T表示转置)。

对于λ2 = 4,我们解方程组(A - 4I)v = 0,得到另一个特征向量v2 = [1, 1]^T。

现在,我们可以验证特征根的含义。对于特征向量v1 = [1, -1]^T,矩阵A作用在这个向量上得到的结果是: Av1 = A[1, -1]^T = [3 * 1 + 1(-1), 1 1 + 3*(-1)]^T = [2, -2]^T = 2*v1

可以看到,矩阵A将特征向量v1伸缩了2倍,这与我们找到的特征根λ1 = 2是一致的。

同样地,对于特征向量v2 = [1, 1]^T,矩阵A作用在这个向量上得到的结果是: Av2 = A[1, 1]^T = [3 * 1 + 1 * 1, 1 * 1 + 3 * 1]^T = [4, 4]^T = 4*v2

矩阵A将特征向量v2伸缩了4倍,这与我们找到的特征根λ2 = 4也是一致的。

通过这个例子,我们可以看到特征根确实表示了矩阵对应的线性变换在特定方向上的伸缩因子。

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import adfuller, kpss
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# 定义一个2x2矩阵
A = np.array([[3, 1],
              [1, 3]])

# 使用numpy.linalg.eig函数计算特征根和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)

print("特征根:", eigenvalues)
print("特征向量:\n", eigenvectors)

# 生成一个非平稳的时间序列数据
np.random.seed(0)
data = np.cumsum(np.random.randn(100))

# 将数据转换为pandas的Series对象
data_series = pd.Series(data)

# 绘制时间序列图
# data_series.plot()

# 进行DF检验
result_df = adfuller(data_series)

# 输出DF检验结果
print('ADF Statistic:', result_df[0])
print('p-value:', result_df[1])
print('Critical Values:', result_df[4])

# 根据p-value判断是否拒绝原假设
if result_df[1] < 0.05:
    print('拒绝原假设,序列是平稳的')
else:
    print('接受原假设,序列是非平稳的')


# 进行ADF检验
result_adf = adfuller(data_series, regression='c', autolag='AIC')

# 输出ADF检验结果
print('ADF Statistic:', result_adf[0])
print('p-value:', result_adf[1])
print('Critical Values:', result_adf[4])

# 根根据p-value判断是否拒绝原假设
if result_adf[1] < 0.05:
    print('拒绝原假设,序列是平稳的')
else:
    print('接受原假设,序列是非平稳的')

# 进行KPSS检验
result_kpss = kpss(data_series, regression='c')

# 输出KPSS检验结果
print('KPSS Statistic:', result_kpss[0])
print('p-value:', result_kpss[1])
print('Critical Values:', result_kpss[3])

# 根据p-value判断是否拒绝原假设
if result_kpss[1] > 0.05:
    print('拒绝原假设,序列是平稳的')
else:
    print('接受原假设,序列是非平稳的')
特征根: [4. 2.]
特征向量:
 [[ 0.70710678 -0.70710678]
 [ 0.70710678  0.70710678]]
ADF Statistic: -1.1320384625097901
p-value: 0.7021277385898382
Critical Values: {'1%': -3.498198082189098, '5%': -2.891208211860468, '10%': -2.5825959973472097}
接受原假设,序列是非平稳的
ADF Statistic: -1.1320384625097901
p-value: 0.7021277385898382
Critical Values: {'1%': -3.498198082189098, '5%': -2.891208211860468, '10%': -2.5825959973472097}
接受原假设,序列是非平稳的
KPSS Statistic: 1.1001161286471666
p-value: 0.01
Critical Values: {'10%': 0.347, '5%': 0.463, '2.5%': 0.574, '1%': 0.739}
接受原假设,序列是非平稳的
C:\Users\win10\AppData\Local\Temp\ipykernel_15296\3430932899.py:56: InterpolationWarning: The test statistic is outside of the range of p-values available in the
look-up table. The actual p-value is smaller than the p-value returned.

  result_kpss = kpss(data_series, regression='c')

DF检验,也称为Dickey-Fuller检验,是一种用于检验时间序列数据是否含有单位根的统计方法。单位根是指一个时间序列的期望值不为零,但其自协方差函数仅依赖于时间间隔的长度,而不依赖于时间的起点。这种特性使得时间序列数据表现出非平稳性,即它们的统计特性会随时间变化。DF检验的基本思想是通过检验时间序列的回归模型中的自回归系数是否为零来确定是否存在单位根。以下是DF检验的相关信息:

DF检验的基本原理

DF检验通过检验时间序列的回归模型中的自回归系数是否为零来确定是否存在单位根。如果自回归系数显著不为零,则表明序列含有单位根,即序列是非平稳的。

DF检验的应用场景

DF检验广泛应用于经济学、金融学和统计学等领域,用于检验时间序列数据的平稳性。例如,在经济学中,它可以帮助分析经济增长率、通货膨胀率等时间序列数据的稳定性。

DF检验的优缺点

优点:DF检验是一种简单且易于实施的统计方法,适用于均值比较的问题,并且可以处理样本大小不一致的情况。 缺点:DF检验对样本数据的正态性有一定要求,如果数据不符合正态分布,可能会影响检验结果的准确性。它只能比较两个样本均值之间的差异,不能提供对多个样本进行比较的信息。

DF检验与ADF检验的区别

DF检验是最早提出的单位根检验方法之一,它是建立在一个简单的自回归模型(AR(1))上的。相比之下,ADF检验使用了更复杂的自回归模型,并且引入了趋势项来对序列的趋势进行建模,从而提高了检验的适用性和准确性。 DF检验只能应用于一阶情况,当序列存在高阶的滞后相关时,可以使用ADF检验,所以说ADF是对DF检验的扩展。

import statsmodels.api as sm
import numpy as np

# 假设我们有以下数据
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 3, 4, 5, 6])
print(x)
# 添加截距项
x = sm.add_constant(x)

print(x)

# 拟合线性回归模型
# model = sm.OLS(y, x).fit()

# # 输出模型摘要
# print(model.summary())

# # 预测
# predictions = model.predict(x)
# print("预测值:", predictions)
[1 2 3 4 5]
[[1. 1.]
 [1. 2.]
 [1. 3.]
 [1. 4.]
 [1. 5.]]

赫斯特(Hurst)指数

赫斯特(Hurst)指数是一种用于分析时间序列数据的统计工具,主要用于衡量时间序列的长期记忆性或自相关性。赫斯特指数是由英国水文学家哈罗德·赫斯特(Harold Edwin Hurst)在20世纪50年代提出的,最初用于分析尼罗河的水位变化。

赫斯特指数的取值范围在0到1之间,可以分为以下几种情况:

H = 0.5:时间序列是随机的,没有自相关性。这种情况下,时间序列的未来值与过去值之间没有任何关系。

0.5 < H < 1:时间序列具有长期记忆性,即未来的趋势与过去的趋势有关。这种情况下,时间序列呈现出持久性(persistence),即如果过去是上升的,未来也很可能继续上升;如果过去是下降的,未来也很可能继续下降。

0 ≤ H < 0.5:时间序列具有反记忆性(antipersistence),即未来的趋势与过去的趋势相反。这种情况下,时间序列呈现出均值回归(mean reversion)的特性,即如果过去是上升的,未来很可能下降;如果过去是下降的,未来很可能上升。

赫斯特指数的计算方法有很多种,其中最常用的是重标极差法(Rescaled Range Analysis, R/S)。以下是计算赫斯特指数的基本步骤:

  1. 将时间序列分成若干个等长的子序列。
  2. 对每个子序列计算累积和(cumulative sum)。
  3. 对每个子序列计算标准差(standard deviation)。
  4. 计算每个子序列的重标极差(rescaled range),即累积和的最大值与最小值之差除以子序列的标准差。
  5. 计算整个时间序列的重标极差均值。
  6. 根据重标极差均值和时间序列的长度计算赫斯特指数。

赫斯特指数在许多领域都有广泛的应用,如金融市场分析、气象学、水文学、地球物理学等。通过计算赫斯特指数,可以帮助我们了解时间序列数据的特性,预测未来趋势,以及评估不同时间序列之间的相关性。

方差比检验

(Variance Ratio Test)是一种用于检验两个或多个独立样本方差是否相等的统计方法。它基于F分布,通过比较两组数据的方差来判断它们是否来自具有相同方差的总体。

方差比检验的步骤如下:

提出假设:

原假设(H0):两组数据的方差相等。 备择假设(H1):两组数据的方差不等于相等。 计算检验统计量:

计算两组数据的样本方差 ( s_1^2 ) 和 ( s_2^2 )。 计算方差比 ( VR = ) 或 ( VR = ),具体取决于哪组数据的方差较大。 根据样本大小 ( n_1 ) 和 ( n_2 ),查找F分布表,确定临界值 ( F_{/2} ) 和 ( F_{1-/2} )。 做出决策:

如果 ( VR ) 落在拒绝域内(即 ( VR < F_{/2} ) 或 ( VR > F_{1-/2} )),则拒绝原假设,认为两组数据的方差不等于相等。 如果 ( VR ) 落在接受域内,则不拒绝原假设,认为两组数据的方差相等。 方差比检验的适用条件包括:

样本是独立的。 样本来自正态分布的总体。 方差比检验通常用于比较两个独立样本的方差,但也可以扩展到多个样本的情况。 需要注意的是,方差比检验对样本大小和分布的正态性有一定的要求。如果样本大小较小或数据分布偏离正态性,检验结果可能不准确。在实际应用中,可以考虑使用其他统计方法,如Levene检验或Bartlett检验,来检验方差的齐性。

半衰期检验

半衰期检验(Half-Life Test)是一种用于评估放射性物质衰变速率的实验方法。在核物理学、化学和环境科学等领域,半衰期检验被广泛应用于研究放射性同位素的衰变特性。通过测量放射性物质在一定时间内的衰变量,可以计算出其半衰期,从而了解其衰变速率和放射性强度。

半衰期检验的基本原理是:在一个封闭系统中,放射性物质的原子核会随着时间的推移逐渐衰变成其他元素或同位素。在衰变过程中,放射性物质的剩余量会按照一定的规律减少。半衰期是指放射性物质剩余量减少到原来的一半所需的时间。

进行半衰期检验的步骤如下:

准备样品:选择一个合适的放射性物质样品,并将其置于一个封闭的容器中。

测量初始放射性强度:使用辐射探测器测量样品的初始放射性强度。

等待一段时间:等待足够长的时间,使得样品的放射性强度发生明显变化。

再次测量放射性强度:在等待时间结束后,再次使用辐射探测器测量样品的放射性强度。

计算半衰期:根据两次测量的放射性强度和时间间隔,使用以下公式计算半衰期:

[ t_{1/2} = ]

其中,( t_{1/2} ) 是半衰期,( (2) ) 是自然对数的底数(约等于 0.693),( k ) 是衰变速率常数。

分析结果:根据计算出的半衰期,分析放射性物质的衰变速率和放射性强度。

需要注意的是,半衰期检验需要在专业的实验室环境中进行,并采取适当的安全措施,以防止辐射对人体的伤害。此外,半衰期检验的结果可能受到测量误差和其他因素的影响,因此需要进行多次实验并取平均值以提高准确性。

半衰期检验(Half-Life Test)本身并不是专门用于测试时间序列的回归性和平稳性的方法。半衰期检验主要用于评估放射性物质衰变速率,而不是时间序列分析

计算半衰期(Half-life)的方法在金融和其他领域中通常用于衡量均值回复(mean reversion)的速度。在你的代码中,半衰期是通过对时间序列数据进行自回归分析(AR模型)得到的。这种方法基于统计学中的自回归模型(Autoregressive Model),特别是AR(1)模型。

理论依据

AR(1) 模型

在一个AR(1)模型中,当前值 $ y_t $ 可以通过前一期的值 $ y_{t-1} $ 和一个随机误差项 $ t $ 来预测: $ y_t = + y{t-1} + _t $

其中: - $ $ 是截距项; - $ $ 是自回归系数; - $ _t $ 是随机误差项,通常假定服从正态分布 $ N(0, ^2) $。

均值回复

如果 $ $ 在 (-1, 1) 区间内,那么该时间序列具有均值回复特性。如果 $ < 1 $,则随着时间的推移,时间序列倾向于返回其长期平均值。如果 $ > 1 $,则时间序列表现出“爆炸”趋势,远离其平均值。

半衰期计算

半衰期是指时间序列回归其长期平均值所需的时间长度的一半。在AR(1)模型中,半衰期可以通过以下公式计算: $ = - $

在你的代码中,$ $ 是通过线性回归 $ y_t $ 对 $ y_{t-1} $ 得到的,这里的 $ y_t $ 表示 $ y_t $ 与其滞后一期的差分: $ y_t = y_t - y_{t-1} $

然后构建一个带有常数项的线性回归模型: $ y_t = + y_{t-1} + _t $

最后,根据回归得到的 $ $ 计算半衰期。

代码解释

  1. 创建滞后变量ylag = y.shift() 创建一个滞后一期的时间序列。
  2. 计算差分deltay = y - ylag 计算当前值与滞后值的差分。
  3. 移除首行NaNdeltay = deltay[1:] 移除由于滞后产生的首行NaN值。
  4. 添加常数项X = sm.add_constant(ylag[1:]) 为滞后变量添加常数项。
  5. 创建并拟合模型:使用普通最小二乘法(OLS)创建并拟合线性回归模型。
  6. 计算半衰期:根据回归系数 ( ) 计算半衰期。

这种方法在实践中广泛应用于算法交易、统计套利策略等场景中,以评估资产价格或策略收益的均值回复特性。

协整关系

协整关系(Cointegration)是时间序列分析中的一个重要概念,它描述了两个或多个非平稳时间序列之间存在的长期稳定关系。

在经济学和金融学中,协整关系常用于分析不同经济变量之间的长期均衡关系。例如,协整关系可以用来检验两个经济指标(如价格和工资)是否长期同步变动,从而判断它们之间是否存在长期的均衡关系。

协整关系的存在需要满足一定的条件,包括:

  1. 变量的非平稳性:协整关系通常存在于非平稳的时间序列之间。如果所有变量都是平稳的,那么它们之间就不存在协整关系。
  2. 长期稳定性:协整关系描述的是变量之间的长期稳定关系。即使短期内变量之间可能出现波动或偏离,但在长期内它们会回归到均衡状态。
  3. 最小二乘法估计的有效性:在存在协整关系的情况下,可以使用最小二乘法(OLS)对回归模型进行估计,并且得到的估计量是一致的。

协整关系的检验通常使用Engle-Granger两步法或其他更复杂的统计方法。如果检验结果表明变量之间存在协整关系,那么就可以进一步分析它们之间的长期均衡关系,并进行相关的预测和政策分析。

协整型ADF检验

协整型ADF检验(Cointegration Augmented Dickey-Fuller Test)是一种用于检验两个或多个非平稳时间序列是否存在协整关系的统计方法。协整关系指的是两个或多个时间序列之间存在长期的稳定关系,即使它们各自是非平稳的。

在进行协整型ADF检验之前,通常需要先对时间序列进行单位根检验,以确定它们是否为非平稳的。如果两个时间序列都是非平稳的,但它们的线性组合是平稳的,那么这两个时间序列之间存在协整关系。

协整型ADF检验的基本步骤如下:

单位根检验:首先对两个或多个时间序列分别进行单位根检验,确定它们是否为非平稳的。常用的单位根检验方法有 Augmented Dickey-Fuller (ADF) 检验和 Phillips-Perron (PP) 检验。

估计协整关系:如果两个时间序列都是非平稳的,接下来需要估计它们之间的协整关系。这可以通过最小二乘法或其他回归方法来实现。

协整型ADF检验:在估计出协整关系后,进行协整型ADF检验。这个检验实际上是检验残差序列是否平稳。如果残差序列是平稳的,那么两个时间序列之间存在协整关系;否则,它们之间不存在协整关系。

解释结果:根据协整型ADF检验的结果,可以得出两个时间序列之间是否存在协整关系的结论。如果存在协整关系,那么可以利用这个关系进行预测和分析。

需要注意的是,协整型ADF检验对样本大小和数据质量有一定的要求。如果样本太小或数据存在严重的自相关或异方差问题,检验结果可能不准确。在实际应用中,可以考虑使用其他协整检验方法,如 Engle-Granger 两步法或 Johansen 协整检验。

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import adfuller
from statsmodels.regression.linear_model import OLS

# 生成两个非平稳的时间序列
np.random.seed(42)
n = 100
x = np.cumsum(np.random.randn(n))
y = 2 * x + np.cumsum(np.random.randn(n))

# 单位根检验
result_x = adfuller(x)
result_y = adfuller(y)

print("x 的单位根检验结果:", result_x)
print("y 的单位根检验结果:", result_y)

# 估计协整关系
model = OLS(y, x).fit()
residuals = model.resid

# 协整型ADF检验
result_residuals = adfuller(residuals)

print("残差序列的单位根检验结果:", result_residuals)

# 解释结果
alpha = 0.05
if result_x[1] > alpha and result_y[1] > alpha and result_residuals[1] < alpha:
    print("x 和 y 存在协整关系")
else:
    print("x 和 y 不存在协整关系")
x 的单位根检验结果: (-1.3583317659818985, 0.6020814791099101, 0, 99, {'1%': -3.498198082189098, '5%': -2.891208211860468, '10%': -2.5825959973472097}, 222.8689980232281)
y 的单位根检验结果: (-1.258001500815765, 0.6481611011736785, 1, 98, {'1%': -3.4989097606014496, '5%': -2.891516256916761, '10%': -2.5827604414827157}, 356.0626708213774)
残差序列的单位根检验结果: (-1.9559190170990346, 0.3062290299375441, 0, 99, {'1%': -3.498198082189098, '5%': -2.891208211860468, '10%': -2.5825959973472097}, 237.03854879262025)
x 和 y 不存在协整关系

约翰森测试(Johansen Test),也称为约翰森协整检验(Johansen Cointegration Test),是一种用于检验多个非平稳时间序列之间是否存在长期稳定关系的统计方法。这种方法是基于向量自回归(VAR)模型,通过估计模型参数并构造相应的统计量来检验协整关系的存在性。以下是关于约翰森测试的详细介绍:

约翰森测试的基本原理

约翰森测试的核心思想是,如果两个或多个非平稳时间序列之间存在协整关系,那么它们的线性组合应该是平稳的。通过构建一个向量自回归(VAR)模型,并估计模型参数,可以检验这些时间序列的协整关系。

约翰森测试的主要步骤

  1. 建立VAR模型:首先确定VAR模型的最优滞后阶数,并估计模型参数。
  2. 计算残差:对VAR模型进行估计后,计算模型的残差。
  3. 单位根检验:对残差进行单位根检验,以判断是否存在协整关系。

约翰森测试的结果解读

  • 特征值:特征值表示每个潜在协整关系的强度。特征值越接近1,表示协整关系越强。
  • 特征向量:特征向量表示协整关系的方向。
  • 似然比统计量:用于检验是否存在协整关系以及协整关系的数量。
  • 临界值:用于确定似然比统计量是否显著。

约翰森测试的应用场景

约翰森测试广泛应用于经济学和金融学领域,特别是用于研究股票价格、汇率、利率等变量之间的长期均衡关系。它可以帮助分析师判断两个或多个时间序列之间是否存在长期的稳定关系,从而为投资决策提供依据。

约翰森测试与相关性检验的区别

  • 协整性:描述的是两个或多个非平稳时间序列之间存在的一种长期稳定关系。
  • 相关性:衡量的是两个时间序列之间的线性关系强度。

约翰森测试的结果可以帮助我们避免使用非平稳数据进行回归分析所导致的“伪回归”问题,从而更准确地分析变量之间的长期均衡关系。在实际操作中,交易者通常会结合其他技术指标和市场分析来综合判断股票之间的协整性,以制定更为有效的交易策略。

import numpy as np  
import pandas as pd  
from statsmodels.tsa.vector_ar.vecm import coint_johansen  
  
# 生成模拟数据  
np.random.seed(42)  
t = np.linspace(0, 10, 100)  
x1 = np.sin(t) + np.random.normal(0, 0.1, 100)  
x2 = np.cos(t) + np.random.normal(0, 0.1, 100)  
x3 = 0.5 * x1 + 0.5 * x2 + np.random.normal(0, 0.1, 100)  
  
# 将数据转换为DataFrame  
data = pd.DataFrame({'X1': x1, 'X2': x2, 'X3': x3})  
print(data)
# 使用Johansen协整检验  
model = coint_johansen(data, det_order=0, k_ar_diff=1)  
  
# 打印结果  
print("Johansen协整检验结果:")  
print("\n--- 迹统计量(Trace Statistics, lr1)---")  
print(model.lr1)  
print("\n--- 临界值(Critical Values,通常为1%、5%、10%显著性水平)---")  
print(model.cvt)  
print("\n--- 最大特征值统计量(Maximum Eigenvalue Statistics, lr2)---")  
print(model.lr2)  
print("\n--- 临界值(Critical Values,通常为1%、5%、10%显著性水平)---")  
print(model.cvm)  
  
# 解释结果并打印的函数  
def print_rejection(stat, cv, name, significance_level=0.05):  
    # 将显著性水平转换为列索引(cvt的第一行通常是显著性水平说明,从第二行开始是临界值)  
    sig_levels = ['1%', '5%', '10%']  # 假设cvt的列标题是这样,实际情况可能不同  
    col_index = sig_levels.index(f"{significance_level*100:.0f}%")  
    if col_index == -1:  # 如果指定的显著性水平不在列表中,则默认使用5%  
        col_index = 1  
    print('cv[0]:',cv[0])
    print('col_index:',col_index)
    num_rejections = 0  
    for value, c_value in zip(stat, cv[:, col_index]):  
        if value > c_value:  
            num_rejections += 1  
            print(f"在{name}检验中,拒绝了不存在至少{num_rejections}个协整向量的原假设(统计量={value:.2f}{significance_level*100:.0f}%临界值={c_value:.2f})")  
        else:  
            break  
  
print_rejection(model.lr1, model.cvt, "迹",significance_level=0.05)
print_rejection(model.lr2, model.cvm, "最大特征值")  
  
# 得出结论  
# 注意:由于迹统计量和最大特征值统计量可能会给出不同的结论,  
# 我们通常根据其中一个或结合两者来得出结论。  
# 在这里,我们简单地基于迹统计量的结果来得出结论。  
col_idx = 1
print('model.lr1 > model.cvt[:, col_idx]:',model.lr1 > model.cvt[:, col_idx])
print('np.any(model.lr1 > model.cvt[:, col_idx]):',np.any(model.lr1 > model.cvt[:, col_idx]))
if np.any(model.lr1 > model.cvt[:, col_idx]):  # 检查是否有拒绝发生  
    num_cointegrating_vectors = np.sum(model.lr1 > model.cvt[:, col_idx])  
    print(f"\n结论:时间序列之间存在至少{num_cointegrating_vectors}个协整向量(基于迹统计量)。")  
else:  
    print("\n结论:时间序列之间不存在协整向量(基于迹统计量)。")  
  
# 注意:实际中,你可能需要更仔细地分析两个统计量的结果,  
# 并考虑数据的性质、样本大小、滞后阶数的选择等因素来综合得出结论。
          X1        X2        X3
0   0.049671  0.858463  0.489846
1   0.087012  0.952838  0.576004
2   0.265418  0.945392  0.713710
3   0.450717  0.874209  0.767843
4   0.369721  0.903352  0.498769
..       ...       ...       ...
95 -0.316698 -0.946852 -0.701066
96 -0.239231 -1.051570 -0.555440
97 -0.338493 -0.915792 -0.596413
98 -0.456126 -0.883832 -0.588693
99 -0.567480 -0.953369 -0.697461

[100 rows x 3 columns]
Johansen协整检验结果:

--- 迹统计量(Trace Statistics, lr1)---
[144.34074724  83.97031191  37.69871001]

--- 临界值(Critical Values,通常为1%、5%、10%显著性水平)---
[[27.0669 29.7961 35.4628]
 [13.4294 15.4943 19.9349]
 [ 2.7055  3.8415  6.6349]]

--- 最大特征值统计量(Maximum Eigenvalue Statistics, lr2)---
[60.37043533 46.2716019  37.69871001]

--- 临界值(Critical Values,通常为1%、5%、10%显著性水平)---
[[18.8928 21.1314 25.865 ]
 [12.2971 14.2639 18.52  ]
 [ 2.7055  3.8415  6.6349]]
cv[0]: [27.0669 29.7961 35.4628]
col_index: 1
在迹检验中,拒绝了不存在至少1个协整向量的原假设(统计量=144.34,5%临界值=29.80)
在迹检验中,拒绝了不存在至少2个协整向量的原假设(统计量=83.97,5%临界值=15.49)
在迹检验中,拒绝了不存在至少3个协整向量的原假设(统计量=37.70,5%临界值=3.84)
cv[0]: [18.8928 21.1314 25.865 ]
col_index: 1
在最大特征值检验中,拒绝了不存在至少1个协整向量的原假设(统计量=60.37,5%临界值=21.13)
在最大特征值检验中,拒绝了不存在至少2个协整向量的原假设(统计量=46.27,5%临界值=14.26)
在最大特征值检验中,拒绝了不存在至少3个协整向量的原假设(统计量=37.70,5%临界值=3.84)
model.lr1 > model.cvt[:, col_idx]: [ True  True  True]
np.any(model.lr1 > model.cvt[:, col_idx]): True

结论:时间序列之间存在至少3个协整向量(基于迹统计量)。