\( \newcommand{\E}{\mathbb{E}} \newcommand{\Var}{\operatorname{Var}} \newcommand{\Cov}{\operatorname{Cov}} \newcommand{\Prob}{\mathbb{P}} \newcommand{\R}{\mathbb{R}} \newcommand{\N}{\mathbb{N}} \newcommand{\iid}{\overset{\text{i.i.d.}}{\sim}} \newcommand{\dto}{\xrightarrow{d}} \newcommand{\pto}{\xrightarrow{p}} \newcommand{\diff}{\mathop{}\!\mathrm{d}} \)

ADF 検定(拡張ディッキー・フラー検定)

時系列
単位根
時系列に単位根があるかを調べる検定。帰無分布が正規分布にならない理由と、検出力の低さ。
公開

2026年9月27日

何を調べる検定か

時系列 \(y_t\) が 単位根(unit root)を持つか、つまりランダムウォークのように ショックが永久に残る過程かどうかを調べる。

最も簡単な AR(1) で考える。 \[ y_t = \phi\, y_{t-1} + \varepsilon_t, \qquad \varepsilon_t \iid (0, \sigma^2). \]

  • \(|\phi| < 1\) なら定常。ショックは指数的に減衰する。
  • \(\phi = 1\) ならランダムウォーク \(y_t = y_0 + \sum_{s=1}^t \varepsilon_s\)。\(\Var(y_t) = t\sigma^2\) で発散する。

両辺から \(y_{t-1}\) を引き、\(\gamma = \phi - 1\) とおくと検定しやすい形になる。 \[ \Delta y_t = \gamma\, y_{t-1} + \varepsilon_t . \]

検定の組み立て

ADF 検定は、確定項と \(\Delta y\) のラグを加えた次の回帰を OLS で推定する。 \[ \Delta y_t = \underbrace{\alpha + \beta t}_{\text{確定項}} + \gamma\, y_{t-1} + \sum_{i=1}^{p} \delta_i\, \Delta y_{t-i} + \varepsilon_t . \]

仮説 内容
\(H_0: \gamma = 0\) 単位根あり(非定常)
\(H_1: \gamma < 0\) 単位根なし(定常。確定項があればトレンド定常)

検定統計量は通常の \(t\) 値と同じ形をしている。 \[ \tau = \frac{\hat\gamma}{\operatorname{se}(\hat\gamma)} . \]

ラグ \(\sum \delta_i \Delta y_{t-i}\) は、誤差の系列相関を吸収して \(\varepsilon_t\) を白色雑音に近づけるために入れる。 \(p\) は AIC や BIC で選ぶのが普通。

確定項の入れ方で3通りに分かれ、それぞれ臨界値が違う。

ケース 回帰に含めるもの 対立仮説のイメージ 5% 臨界値(漸近)
1 なし 0 のまわりの定常 \(-1.95\)
2 定数 \(\alpha\) 平均 \(\ne 0\) の定常 \(-2.86\)
3 定数 \(\alpha\) + トレンド \(\beta t\) トレンド定常 \(-3.41\)

なぜ正規分布の臨界値を使えないのか

\(H_0\) の下では \(y_{t-1}\) が非定常なので、通常の中心極限定理が使えない。 \(\tau\) は標準正規分布には収束せず、ブラウン運動 \(W(r)\) の汎関数に収束する(ケース1)。 \[ \tau \;\dto\; \frac{\tfrac12\left(W(1)^2 - 1\right)}{\left(\int_0^1 W(r)^2 \diff r\right)^{1/2}} . \]

この分布は左に大きくずれている。\(H_0\) の下で \(\tau\) をシミュレーションすると確かめられる(ケース2、\(T = 200\))。

コード
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

plt.rcParams["font.family"] = ["Hiragino Sans", "sans-serif"]
rng = np.random.default_rng(0)

def df_tau(y):
    """ケース2(定数あり、ラグなし)の DF 統計量を行ごとに計算する。y: (R, T)"""
    dy = np.diff(y, axis=1)
    x = y[:, :-1]
    xc = x - x.mean(axis=1, keepdims=True)
    dyc = dy - dy.mean(axis=1, keepdims=True)
    sxx = (xc**2).sum(axis=1)
    g = (xc * dyc).sum(axis=1) / sxx
    resid = dyc - g[:, None] * xc
    n = dy.shape[1]
    s2 = (resid**2).sum(axis=1) / (n - 2)
    return g / np.sqrt(s2 / sxx)

R, T = 20000, 200
y = np.cumsum(rng.standard_normal((R, T)), axis=1)
tau = df_tau(y)

grid = np.linspace(-6, 4, 400)
fig, ax = plt.subplots()
ax.hist(tau, bins=120, density=True, alpha=0.6, label="τ のシミュレーション")
ax.plot(grid, stats.norm.pdf(grid), label="標準正規分布")
q_tau = np.quantile(tau, 0.05)
ax.axvline(q_tau, ls="--", color="C0")
ax.axvline(stats.norm.ppf(0.05), ls="--", color="C1")
ax.set_xlabel("τ")
ax.legend()
plt.show()
print(f"シミュレーションの 5% 点: {q_tau:.2f}   標準正規の 5% 点: {stats.norm.ppf(0.05):.2f}")
図 1: H0(ランダムウォーク)の下での τ の分布(ケース2, T=200, 20000 回)。破線は各分布の 5% 点。
シミュレーションの 5% 点: -2.87   標準正規の 5% 点: -1.64

標準正規の \(-1.645\) で判定すると、単位根があるのに「定常」と判定する誤りが 5% を大きく超えてしまう。

使ってみる

statsmodels の adfuller で、ランダムウォークと定常な AR(1) を比べる。

コード
from statsmodels.tsa.stattools import adfuller

rng = np.random.default_rng(1)
T = 300
eps = rng.standard_normal(T)

def ar1(phi):
    y = np.zeros(T)
    for t in range(1, T):
        y[t] = phi * y[t - 1] + eps[t]
    return y

for name, phi in [("ランダムウォーク φ=1", 1.0), ("AR(1) φ=0.8", 0.8), ("AR(1) φ=0.97", 0.97)]:
    stat, p, lag, n, crit, _ = adfuller(ar1(phi), regression="c", autolag="AIC")
    print(f"{name:18s} τ = {stat:6.2f}  p = {p:.3f}  ラグ = {lag}")
ランダムウォーク φ=1       τ =   0.34  p = 0.979  ラグ = 8
AR(1) φ=0.8        τ =  -5.03  p = 0.000  ラグ = 8
AR(1) φ=0.97       τ =  -2.30  p = 0.171  ラグ = 8

\(\phi = 0.97\) は定常なのに、\(p\) 値が大きく出やすい。次の節で見るように、単位根に近い定常過程を見分ける力は弱い。

検出力が低い

真の \(\phi\) を 1 に近づけていったとき、5% 水準で \(H_0\) を棄却できる割合(検出力)をシミュレーションで調べる。

コード
phis = np.array([0.80, 0.85, 0.90, 0.93, 0.95, 0.97, 0.99, 1.00])
fig, ax = plt.subplots()
for T in [50, 100, 250, 500]:
    power = []
    for phi in phis:
        e = rng.standard_normal((2000, T))
        y = np.zeros_like(e)
        for t in range(1, T):
            y[:, t] = phi * y[:, t - 1] + e[:, t]
        power.append((df_tau(y) < -2.86).mean())
    ax.plot(phis, power, marker="o", label=f"T = {T}")
ax.axhline(0.05, color="gray", lw=0.8)
ax.set_xlabel("真の φ")
ax.set_ylabel("棄却率")
ax.legend()
plt.show()
図 2: ケース2 の DF 検定の検出力(5% 水準, 臨界値 -2.86, 2000 回)。

\(T = 100\) で \(\phi = 0.95\) だと、定常であるのに大半のケースで棄却できない。 「棄却できなかった」ことは「単位根がある」ことの証拠にはならない。

KPSS 検定と組み合わせる

KPSS 検定は仮説の向きが逆で、定常性を帰無仮説にする。両方を行うと判断しやすい。

ADF KPSS 解釈
棄却 棄却しない 定常
棄却しない 棄却 単位根あり
棄却しない 棄却しない データが足りず判断できない
棄却 棄却 構造変化や長期記憶などを疑う

API で試す(準備中)

この検定は api.noisymoon.jp から呼び出せるようにする予定。

POST /v1/tests/adf
{
  "series": [0.12, 0.35, 0.10, ...],
  "regression": "c",
  "autolag": "AIC"
}

参考文献

  • Dickey, D. A. and Fuller, W. A. (1979). Distribution of the estimators for autoregressive time series with a unit root. JASA, 74, 427–431.
  • Said, S. E. and Dickey, D. A. (1984). Testing for unit roots in autoregressive-moving average models of unknown order. Biometrika, 71, 599–607.
  • MacKinnon, J. G. (2010). Critical values for cointegration tests. Queen’s Economics Department Working Paper No. 1227.
  • Hamilton, J. D. (1994). Time Series Analysis. Princeton University Press, Ch. 17.