🎓 レベル:発展 | 重要度:A(必須)
📎 前提:ランダムウォークと単位根(単位根・見せかけの回帰)・VAR(ベクトル自己回帰)(多変量) | 数理:確率過程(マルコフ連鎖・ポアソン過程)(統計)
要点(BLUF)
- 共和分:個々の系列は単位根で非定常(、ランダムウォークと単位根)でも、ある線形結合が定常になるとき、それらは共和分しているといいます。その結合 が長期均衡を表します。
- 見せかけの回帰との違い:無関係な 2 本の単位根過程の回帰は偽物(ランダムウォークと単位根)。しかし共和分があれば、その回帰は本物の長期関係。違いは「残差が定常か」で判定します。
- VECM = 差分 VAR + 誤差修正項。共和分があるのに差分だけ取ると長期情報(均衡へ戻る力)を捨ててしまう。VECM は均衡からのズレを次期にどれだけ戻すか(調整係数 )を明示的にモデル化します。
1. 共和分:非定常どうしの定常な結合
2 系列 がともに (1 階差分で定常)だとします。一般に どうしの和や差も のままですが、特別な係数 では が (定常)になることがあります。これが共和分で、 を共和分ベクトル、 を均衡誤差と呼びます。
直観は「2 つの酔っ払いが鎖でつながれて歩く」像。各自はランダムウォークで好き勝手に動く(非定常)が、鎖の長さ(差)は一定以上に開かない(差は定常)。為替と物価、現物と先物、ペア取引の 2 銘柄などが典型例です。
共通の確率トレンド (ランダムウォーク)を共有すると共和分が生まれます:
このとき は共通トレンド が消えて定常になります。 単体は を含むので (非定常)のままです。
コード①:各々は I(1)・線形結合は定常を確かめ、共和分を検定
共通トレンド を共有する (真の共和分ベクトルは )を生成し、(a) 各系列が ADF で非定常、(b) 線形結合 が ADF で定常、を確かめます。さらに Engle-Granger(coint)と Johansen(coint_johansen)で共和分を検定し、回帰で長期係数を復元します。
import numpy as np
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller, coint
from statsmodels.tsa.vector_ar.vecm import coint_johansen
# 共通の確率トレンド w(ランダムウォーク)を 2 系列で共有 → 共和分
# w_t = w_{t-1} + e_w (共通トレンド・I(1))
# x_t = w_t + e_x (x は w にノイズ)
# y_t = 2 w_t + e_y (y は 2w にノイズ)
# → x も y も I(1) で非定常。だが y - 2x = e_y - 2 e_x は定常(共和分ベクトル [1,-2])
np.random.seed(0)
n = 600
w = np.cumsum(np.random.normal(0, 1, n))
x = w + np.random.normal(0, 0.5, n)
y = 2.0 * w + np.random.normal(0, 0.5, n)
# (a) 各系列は単位根(非定常)か:ADF(p>=0.05 で非定常)
print("各系列の ADF(p>=0.05 で非定常・単位根あり)")
print(f" x: p={adfuller(x)[1]:.3f} y: p={adfuller(y)[1]:.3f}")
# (b) 真の線形結合 y - 2x は定常か
combo = y - 2.0 * x
print(f" y-2x(線形結合): p={adfuller(combo)[1]:.3f} → {'定常' if adfuller(combo)[1]<0.05 else '非定常'}")
# (c) Engle-Granger 共和分検定(帰無=共和分なし。p<0.05 で共和分あり)
t_stat, p_eg, _ = coint(y, x)
print(f"\nEngle-Granger 共和分検定: p={p_eg:.3f} → {'共和分あり' if p_eg<0.05 else '共和分なし'}")
# 回帰で共和分ベクトルを推定(y を x に回帰した傾きは およそ 2)
beta = sm.OLS(y, sm.add_constant(x)).fit().params[1]
print(f"回帰で推定した長期係数(真値 2.0): {beta:.3f}")
# (d) Johansen 検定:共和分ランク(トレース統計量 > 95%臨界値 の数)
joh = coint_johansen(np.column_stack([y, x]), det_order=0, k_ar_diff=1)
trace = joh.lr1 # トレース統計量
cv95 = joh.cvt[:, 1] # 95% 臨界値
rank = int(np.sum(trace > cv95))
print(f"\nJohansen トレース統計量={np.round(trace,2)} 95%臨界値={np.round(cv95,2)}")
print(f"→ 共和分ランク = {rank}(2系列で 1 本の長期均衡関係)")
出力:
各系列の ADF(p>=0.05 で非定常・単位根あり)
x: p=0.990 y: p=0.986
y-2x(線形結合): p=0.000 → 定常
Engle-Granger 共和分検定: p=0.000 → 共和分あり
回帰で推定した長期係数(真値 2.0): 2.003
Johansen トレース統計量=[258.99 0.4 ] 95%臨界値=[15.49 3.84]
→ 共和分ランク = 1(2系列で 1 本の長期均衡関係)
出力の意味: 単体は ADF で =非定常(単位根あり)。ところが線形結合 は =定常——共通トレンドが打ち消されました。Engle-Granger 検定も で共和分ありと判定し、回帰の長期係数は と真値 2.0 を復元。Johansen のトレース統計量は、ランク 0 の帰無で (棄却)、ランク 1 の帰無で (棄却せず)なので共和分ランク=1——2 系列の間に長期均衡関係が 1 本ある、と正しく結論します。これは「非定常どうしの回帰は見せかけ」(ランダムウォークと単位根)の例外=本物の長期関係です。残差が定常か否かが分かれ目。
2. 誤差修正モデル(VECM):均衡へ引き戻す力
共和分があるなら、差分 VAR ではなく VECM(Vector Error Correction Model) を使います。VECM は差分 VAR に誤差修正項を足した形です:
- が前期の均衡誤差(長期均衡からのズレ)。共和分ベクトル が長期関係を、
- が調整係数(誤差修正速度)——「ズレを次期にどれだけ戻すか」。符号と大きさが復元力を表します。 なら戻さない(その変数は均衡から離れても放置)。
- は短期のダイナミクス(差分のラグ)。
flowchart LR
A["2系列 x_t, y_t(各々 I(1)・非定常)"] --> B["共和分検定: 線形結合は定常か"]
B -->|"共和分あり"| C["VECM = 差分VAR + 誤差修正項"]
B -->|"共和分なし"| D["差分してから VAR"]
C --> E["β: 長期均衡 / α: 均衡へ戻す速度"]
E --> F["予測(誤差修正で均衡へ引き戻す)"]
コード②:VECM で誤差修正項を推定・解釈し予測
共和分する に VECM(共和分ランク 1)を当て、共和分ベクトル と調整係数 (誤差修正項)を推定・解釈します。末尾 20 期はホールドアウトして予測区間つきで予測します。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from statsmodels.tsa.vector_ar.vecm import VECM
# 同じ共和分する 2 系列(共通トレンド w を共有)
np.random.seed(0)
n = 600
w = np.cumsum(np.random.normal(0, 1, n))
x = w + np.random.normal(0, 0.5, n)
y = 2.0 * w + np.random.normal(0, 0.5, n)
data = np.column_stack([y, x]) # 列順 [y, x]
h = 20
train = data[:-h]
# VECM:差分VAR + 誤差修正項。共和分ランク1、deterministic='ci'(共和分式に定数)
model = VECM(train, k_ar_diff=1, coint_rank=1, deterministic="ci")
res = model.fit()
# 共和分ベクトル β(正規化:y の係数=1)と 調整係数 α(誤差修正速度)
beta = res.beta[:, 0]
beta_norm = beta / beta[0]
print("共和分ベクトル β([y, x] を正規化, 真の比は y:x = 1:-2):")
print(f" y 係数={beta_norm[0]:.3f} x 係数={beta_norm[1]:.3f}")
print("\n調整係数 α(均衡からのズレを次期にどれだけ戻すか・誤差修正項):")
print(f" Δy への α = {res.alpha[0,0]:.3f}")
print(f" Δx への α = {res.alpha[1,0]:.3f}")
# 予測(点予測 + 95% 予測区間)
point, lower, upper = res.predict(steps=h, alpha=0.05)
test = data[-h:]
for j, name in enumerate(["y", "x"]):
rmse = np.sqrt(np.mean((point[:, j] - test[:, j])**2))
w1 = upper[0, j] - lower[0, j]
wH = upper[-1, j] - lower[-1, j]
print(f"{name}: RMSE={rmse:.3f} 区間幅 1期={w1:.2f}→{h}期={wH:.2f}(水準はI(1)で広がる)")
# 図示(y:実測・点予測・区間)
t_axis = np.arange(n)
plt.figure(figsize=(9, 4.5))
plt.plot(t_axis[-80:-h], train[-80+h:, 0], color="gray", lw=1, label="訓練(実測)")
plt.plot(t_axis[-h:], test[:, 0], color="k", lw=1.5, marker="o", ms=3, label="検証(実測)")
plt.plot(t_axis[-h:], point[:, 0], color="C2", lw=2, label="VECM 点予測")
plt.fill_between(t_axis[-h:], lower[:, 0], upper[:, 0], color="C2", alpha=0.25, label="95%予測区間")
plt.axvline(n-h-1, ls=":", color="k")
plt.xlabel("時点 t"); plt.ylabel("y"); plt.legend()
plt.title("VECM による予測(誤差修正で長期均衡へ引き戻す)")
plt.tight_layout(); plt.show()
出力:
共和分ベクトル β([y, x] を正規化, 真の比は y:x = 1:-2):
y 係数=1.000 x 係数=-2.005
調整係数 α(均衡からのズレを次期にどれだけ戻すか・誤差修正項):
Δy への α = -0.209
Δx への α = 0.422
y: RMSE=12.015 区間幅 1期=8.33→20期=34.70(水準はI(1)で広がる)
x: RMSE=5.986 区間幅 1期=4.42→20期=17.37(水準はI(1)で広がる)
出力の意味:共和分ベクトルは正規化して ——均衡関係 を復元しました(真の )。調整係数は 。解釈は「均衡誤差 が正に大きい( が均衡より高い)とき、 は で下がり、 は で上がる。どちらも を縮める向き」——両変数が協調して均衡へ引き戻します。これが誤差修正のメカニズムです。
予測の水準 RMSE が大きい( で 12.0)のは、 の**水準が共通の確率トレンド(ランダムウォーク)を含み だから——20 期先の水準は本質的に不確実で、区間も と大きく広がります。共和分が縛るのは水準そのものではなく 2 系列の差(スプレッド)**です。次のコード③で「差分だけ取るより VECM が均衡スプレッドをよく予測する」を確かめます。
コード③:共和分を捨てる(差分だけ)と長期情報を失う
「共和分があるのに差分 VAR で済ます」と何を失うか。均衡誤差 を持続的な AR(1) にした共和分 DGP を 100 本生成し、VECM(共和分を使う)と差分 VAR(共和分を捨てる)で 15 期先の均衡スプレッドを予測、out-of-sample の RMSE を比べます。
import numpy as np
import warnings
warnings.simplefilter("ignore")
from statsmodels.tsa.api import VAR
from statsmodels.tsa.vector_ar.vecm import VECM
# 均衡誤差 s を「持続的な AR(1)」にした共和分DGP
# w_t = w_{t-1} + e_w (共通の確率トレンド・I(1))
# s_t = 0.85 s_{t-1} + e_s (均衡からのズレ・定常だが持続的)
# x_t = w_t + 0.3 n_x, y_t = 2 w_t + s_t → y-2x はほぼ s (平均回帰する均衡誤差)
def simulate(seed, n=400):
rng = np.random.default_rng(seed)
w = np.cumsum(rng.normal(0, 1, n))
s = np.zeros(n)
for t in range(1, n):
s[t] = 0.85 * s[t-1] + rng.normal(0, 0.6)
x = w + 0.3 * rng.normal(0, 1, n)
y = 2.0 * w + s
return np.column_stack([y, x])
h = 15
rmse_vecm, rmse_diff = [], []
for seed in range(100): # 100 本のパスで out-of-sample 評価
data = simulate(seed)
train, test = data[:-h], data[-h:]
spread_true = test[:, 0] - 2.0 * test[:, 1]
# VECM(共和分を使う=差分VAR+誤差修正項)
v = VECM(train, k_ar_diff=1, coint_rank=1, deterministic="ci").fit()
sv = v.predict(steps=h)
rmse_vecm.append(np.sqrt(np.mean((sv[:,0]-2*sv[:,1] - spread_true)**2)))
# 差分だけ取った VAR(共和分=長期情報を捨てる)
d = np.diff(train, axis=0)
vd = VAR(d).fit(1).forecast(d[-1:], steps=h)
lev = train[-1] + np.cumsum(vd, axis=0)
rmse_diff.append(np.sqrt(np.mean((lev[:,0]-2*lev[:,1] - spread_true)**2)))
mv, md = np.mean(rmse_vecm), np.mean(rmse_diff)
print(f"均衡スプレッド y-2x の {h}期予測 RMSE(100本平均, out-of-sample)")
print(f" VECM(共和分を使う) = {mv:.3f}")
print(f" 差分VAR(共和分を捨てる) = {md:.3f}")
print(f" 改善率 = {(1-mv/md)*100:.1f}%(VECM が均衡へ引き戻す分だけ有利)")
win = np.mean(np.array(rmse_vecm) < np.array(rmse_diff))
print(f" 100本中 VECM が勝った割合 = {win*100:.0f}%")
出力:
均衡スプレッド y-2x の 15期予測 RMSE(100本平均, out-of-sample)
VECM(共和分を使う) = 1.183
差分VAR(共和分を捨てる) = 1.458
改善率 = 18.8%(VECM が均衡へ引き戻す分だけ有利)
100本中 VECM が勝った割合 = 76%
出力の意味:均衡スプレッドの 15 期先予測 RMSE は、VECM vs 差分 VAR で VECM が 18.8% 良く、100 本中 76% で VECM が勝ちました。理由は明快——差分 VAR はスプレッドを「行ったきり」(ランダムウォーク的)に予測し、均衡へ戻る力を最初から持たない。一方 VECM は誤差修正項 で「ズレていれば戻す」を組み込むので、ズレが大きいほど予測が効きます。共和分があるのに差分だけ取ると、この長期均衡の情報を丸ごと捨てる——それがコスト(過剰差分の一種)です。
3. 数式の直観
- 共和分 = 共通トレンドの相殺:各系列は同じ確率トレンド を抱えて非定常だが、 で が消える。「非定常成分を打ち消す配合」が共和分ベクトル 。
- VECM = 短期(差分)と長期(均衡)の分業: の動きを、 の短期慣性と、 の「均衡へ戻す力」に分けて書く。差分 VAR は前者だけ、VECM は後者も持つ。
- の符号 = 復元力の向き:均衡誤差が正のとき、それを縮める向きに各変数が動く(コード②の )。 がゼロに近い変数は「均衡からの逸脱を自分では直さない(他方が調整する)」——弱外生性の判断にも使えます。
⚠️ よくある誤解・落とし穴
- 「非定常どうしの回帰は常に見せかけ」ではない:共和分があれば本物の長期関係。残差が定常か(ADF・Engle-Granger)で見せかけか本物かを分けます(ランダムウォークと単位根)。
- 「共和分があるのに差分 VAR で済ます」は損:均衡へ戻る情報(誤差修正項)を捨て、長期予測が劣化します(コード③)。共和分検定で 1 本でも見つかれば VECM を検討。
- 「共和分なしでも VECM を当てればよい」ではない:共和分が無いのに VECM を当てると誤った均衡を押し付けます。逆に共和分があるのにレベル VAR を当てると見せかけ。検定で共和分ランクを決めてからモデルを選ぶのが順序。
- 「Engle-Granger だけで十分」ではない:2 変数・1 関係なら EG で足りますが、3 変数以上や複数の共和分関係があるときは Johansen(ランクとベクトルを同時推定)が必要。EG は基準変数の選び方に結果が依存します。
- 「水準予測が当たらない=モデルが悪い」ではない:共和分系は水準(共通トレンド)が本質的に非定常で長期は当たりません。当たるのはスプレッド(均衡関係)。何を予測対象にするかを取り違えないこと。
関連ノート
- ランダムウォークと単位根(単位根・見せかけの回帰・差分=I)
- VAR(ベクトル自己回帰)(VECM の母体——差分 VAR + 誤差修正項)
- [05-02_グレンジャー因果]
- 予測の評価指標と時系列CV(out-of-sample 評価・ウォークフォワード)
- ARMA・ARIMAモデル(過剰差分・差分の I の位置づけ)
- [08-03_確率過程]
- 第5章 多変量時系列 目次
- 時系列分析・予測テキスト 全体目次