餡子付゛録゛

ソフトウェア開発ツールの便利な使い方を紹介。

行列を使った計算で、SURの感じを掴んでみよう

計量の教科書には載っているものの非線形モデルには使えず、内生性を制御できないので顧みられることの少ないSUR *1 をふと思い出したので、手順を確認してみました。

1. 2つの方程式からなるSURモデル

理屈はGreeneのEconometric Analysisに詳しく載っているので参照して欲しいのですが、SURの概要を説明します。
以下の連立方程式を同時推定することを考えます*2

{\displaystyle 
\begin{eqnarray}
  \left\{
    \begin{array}{l}
		y_{1} = X_{1}\beta_1 + \epsilon_{1} \\
		y_{2} = X_{2}\beta_2 + \epsilon_{2}
    \end{array}
  \right.
\end{eqnarray}
}

 yは被説明変数のベクトル、 Xは説明変数の行列、 \betaは係数、 \epsilonは誤差項のベクトルです。添字の数字は方程式を表します。
一つ一つ推定しても良い気がしますが、 \mbox{COV}(\epsilon_1, \epsilon_2) \neq 0の場合は推定量を改善する余地があります。

例えば、天候データが無いときに2つの品種の収穫高と肥料の関係を推定するとして、日照量や気温など2つの方程式に同時に同じような影響を与える要因がある場合、 \mbox{COV}(\epsilon_1, \epsilon_2)という情報も使う方が推定結果は真の値に近づきます。

さて、最初は \mbox{COV}(\epsilon_1, \epsilon_2)の情報が無いので、以下をOLSで推定します。

{\displaystyle 
	\begin{pmatrix}
		y_{1} \\
		y_{2}
	\end{pmatrix}
	=
	\begin{pmatrix}
		X_{1} & 0 \\
		0 & X_{2}
	\end{pmatrix}
	\begin{pmatrix}
		\beta_{1} \\
		\beta_{2}
	\end{pmatrix}
	+
	\begin{pmatrix}
		\epsilon_1 \\
		\epsilon_2
	\end{pmatrix}
}

これで、以下の分散共分散行列 \Sigmaがつくれるようになりました。

{\displaystyle 
	\Sigma= 
	\begin{pmatrix}
		\mbox{COV}(\epsilon_1, \epsilon_1) & \mbox{COV}(\epsilon_1, \epsilon_2) \\
		\mbox{COV}(\epsilon_1, \epsilon_2) & \mbox{COV}(\epsilon_2, \epsilon_2)
	\end{pmatrix}
}

これをウェイトに使って、不均一分散の補正をした回帰(FGLS)をかけます。
つまり、以下のように表記を簡素化して、

{\displaystyle 
	y = X\beta + \epsilon
}

以下のようにGLS推定量を求めます。


\newcommand{\argmin}{\mathop{\rm arg~min}\limits}
{\displaystyle 
	\hat{\beta} = \argmin_{\beta} \space  (y - X \beta)^t ( \Sigma^{-1} \otimes I_n ) (y - X \beta)
}

ここで、 \otimesクロネッカー積、 I_nはn行n列の対角行列、 \Sigma \otimes I_nは共分散を対角成分にとる細胞で構成される行列です。 nは観測数です。後述するコマンドを見れば、何が起きるかは一目瞭然だと思います。

この式を満たすために、 \beta微分して一階条件を出して整理すると、

{\displaystyle 
	\hat{\beta} = (X^t ( \Sigma^{-1} \otimes I_n ) X)^{-1} X^t ( \Sigma^{-1} \otimes I_n ) y
}

となります。 (\Sigma \otimes I_n)^{-1} = \Sigma^{-1} \otimes I_nに注意してください。

2. RによるSUR推定

systemfitパッケージを使えば良いのですが、前節で説明したモデルとの対応関係が分からなくなるので、行列を使って計算します。

#
# データセットの作成
#
set.seed(20181103)
n <- 50 # 標本サイズが小さい方が、OLSとSURの差が出る

l <- rnorm(n, sd=2) # 共分散を持つようにする
e1 <- rnorm(n, sd=1) + l
e2 <- rnorm(n, sd=1) + l

x1 <- runif(n, min=0, max=2)
x2 <- runif(n, min=-2, max=2)
y1 <- 1 + 2*x1 + e1
y2 <- 3 + 2*x2 + e2

X1 <- matrix(c(rep(1, n), x1, rep(0, 2*n)), n, 4)
X2 <- matrix(c(rep(0, 2*n), rep(1, n), x2), n, 4)
X <- rbind(X1, X2)
y <- c(y1, y2)

#
# 以下、実際のSUR推定量の計算
#
# 1段階目のOLS推定量を計算
beta_ols <- solve(t(X)%*%X)%*%t(X)%*%y

# 誤差項を計算
r_e <- y - X %*% beta_ols
r_e1 <- r_e[1:n]
r_e2 <- r_e[(n+1):(2*n)]

# ∑を計算
sigma <- matrix(c(cov(r_e1,r_e1), cov(r_e1,r_e2), cov(r_e1,r_e2), cov(r_e2,r_e2)), 2, 2)

# SUR推定量を計算
beta_sur <- solve(t(X) %*% (solve(sigma) %x% diag(n)) %*% X) %*% t(X) %*% (solve(sigma) %x% diag(n)) %*% y

なお、beta_ols - beta_surで推定量にどれぐらい違いがあるか分かるので、nの値を変えて試してみてください。t値やP値はOLSと同様に計算できます。また、sigma %x% diag(n)とすると、 n  \times nの巨大行列ですが、 \Sigma \otimes I_nがどうなっているか分かります。

*1: すぐに同時性ガガガ…と言われるので、GMMか3SLS、もしくは全情報最尤法を使うのが一般的で、SUR自体は3SLSを学ぶ前の予備知識的な扱いが多いと思います。

*2:もっとも単純なモデルを考えましたが、二つの式で、係数が同じ値を持つような制約を置くこともできます。

相関行列から一定以上の大きさの変数の組み合わせを抽出

100や1000もある説明変数同士の相関係数を見るはだるいと言う話があって、確かに100×100や1000×1000どころか、10×10の行列でも目視で確認すると見落としが出そうです。相関係数0.5以上をリストするコードを書いてみましょう。

# テスト用のデータフレームを作る
set.seed(20180925)

n <- 100 # 変数の長さ
m <- 100 # 変数の種類
df1 <- data.frame(x001 = rnorm(n))
for(i in 2:m){
  vn <- sprintf("x%03d", i)
  df1[vn] <- rnorm(n)
  # 以下、ランダムに、既に生成済みの変数からの影響を加える
  xi <- as.integer(runif(1, max=i))
  if(0<xi){
    xn <- sprintf("x%03d", xi)
    beta <- runif(1, min=-1, max=1)
    df1[vn] <- df1[vn] + beta*df1[xn]
  }
}

# だるさを確認
cor(df1)

# 機械的相関係数が0.5より大なものを選ぶ
t <- 0.5
n <- names(df1)
l <- length(n)
s <- 1:l^2-1
flag <- c(abs(cor(df1))>t) # 相関係数がtより大なものはTRUE
flag[seq(1, l^2, l + 1)] <- FALSE # 自己相関は排除

# 結果表示
pair <- sprintf("cor(%s,%s)>%.1f", n[floor(s/l) + 1], n[s %% l + 1], t)
pair[flag]

9900の組み合わせを目視するよりはましですが、116個も出てくるとどれを落とそうか迷いそうですね。こういう状態で回帰分析をするときは、L1/L2正則化項を加えるか、主成分分析などで変数をまとめた方が良さそうです。やはり見る意味はないかも知れません。

よくある操作変数法(IV)のための練習データとOLSによる推定バイアス

内生性について上手くツイートでは問題点を説明できないので、念頭に置いているコードを出します。

#
# 教科書例の需要と供給のデータを作る
# 真のモデル:
# S = 2 + 3*p + 4*z + ν
# D = 1 - 1*p + μ
# S = D
# p:価格, S:供給, D:需要, z:気候か何か, νとμ:誤差項
# → 価格について式を整理してみると、D=Sと言う式から、P = (2 - 1)/(-1 - 3) + 4・z/(-1 - 3) + (ν - μ)/(-1 - 3)になって、Pに推定する需要関数の誤差項μが含まれていることになり、OLSの条件を満たしません。
#
set.seed(20180411)
obs <- 300 # 観測数(増やしてバイアスの変化をチェック!)
a0 <- 1
a1 <- -1
b0 <- 2
b1 <- 3
b2 <- 4
z <- runif(obs, min=0, max=3)
mu <- rnorm(obs, mean=0, sd=2)
nu <- rnorm(obs, mean=0, sd=1)
p <- (b0 - a0 + b2*z + nu - mu)/(a1 - b1)
df1 <- data.frame(
  p = p,
  d = a0 + a1*p + mu,
  s = b0 + b1*p + b2*z + nu
)
rm(p)

#
# OLSで推定してみる
# → バイアスが入る
#
r_ols <- lm(d ~ p, data=df1)


#
# クロスセクションチェック
# → バイアスは同じまま
#
r_ols_css1 <- lm(d ~ p, data=df1[seq(1, obs, 2), ])
r_ols_css2 <- lm(d ~ p, data=df1[seq(2, obs, 2), ])

#
# tslsパッケージを使えば済む操作変数法
# → バイアスは入らない
#
attach(df1)
zm <- matrix(c(rep(1, obs), c(z)), obs, 2)
xm <- matrix(c(rep(1, obs), c(p)), obs ,2)
iv_estimated_a <- solve(t(zm) %*% xm) %*% (t(zm) %*% d)
detach(df1)

#
# 推定結果の中身を比較してみる
#
print_dc <- function(label, a){
  sprintf("%s: D = %.04f%s%.04fp", label, a[1], ifelse(a[2]>=0,"+",""), a[2])
}

paste(c(
  print_dc("OLS", coef(r_ols)),
  print_dc("CSS01", coef(r_ols_css1)),
  print_dc("CSS02", coef(r_ols_css2)),
  print_dc("IV", iv_estimated_a)))

FE-IV練習用データ生成

dとsの式でpが内生変数、zが操作変数ですが、こんなんで。

noi <- 20 # 個体数
t <- 5 # 観測期間
obs <- t*noi
i <- c(t(replicate(t, 1:(noi))))
fe <- runif(noi, min=0, max=100)
a0 <- c(t(replicate(t, fe)))
a1 <- -1
b0 <- 2
b1 <- 3
b2 <- 4
z <- runif(obs, min=0, max=3)
mu <- rnorm(obs, mean=0, sd=2)
nu <- rnorm(obs, mean=0, sd=1)
p <- (b0 - a0 + b2*z + nu - mu)/(a1 - b1)
d <- a0 + a1*p + mu
s <- b0 + b1*p + b2*z + nu

within変換をかけてIVで推定

within_transfer <- function(x, i){
  m <- tapply(x, i, mean)
  x - c(t(replicate(t, m)))
}

w_d <- within_transfer(d, i)
w_z <- within_transfer(z, i)
w_p <- within_transfer(p, i)

zm <- matrix(c(c(w_z)), obs, 1)
xm <- matrix(c(c(w_p)), obs ,1)
estimated_a1 <- solve(t(zm) %*% xm) %*% (t(zm) %*% w_d)

観測数obsが2000ぐらい無いと誤差多し

Stata風に切片項を計算する

estimated_mu <- w_d - estimated_a1 %*% w_p

ma_d <- mean(d)
mi_d <- c(t(replicate(t,tapply(d, i, mean))))

ma_z <- mean(z)
mi_z <- c(t(replicate(t,tapply(z, i, mean))))

ma_p <- mean(p)
mi_p <- c(t(replicate(t,tapply(p, i, mean))))

estimated_a0 <- (d - mi_d + ma_d) - (p - mi_p + ma_p)*c(estimated_a1) - c(estimated_mu)

ゲーム理論で考える、じゃんけんの拡張の数値演算

ゲーム理論で考える、じゃんけんの拡張: ニュースの社会科学的な裏側で使ったコードです。通常のゲーム理論の数値演算で扱われる計算手順に習っていないと言うか、フィーリングで描いたので、何か勘違いがあるかも知れないです。

##########################
### 引き分けになる確率 ###
##########################

p_even <- function(n){
  if(1>n){
    return(0)
  }
  1-(2^n-2)/3^(n-1)
}


##########################
### 確定的確率質量関数計算 ###
##########################

mkdist <- function(p){
  d2b <- function(num, digits=8){
    r <- numeric(digits)
    for(i in (digits-1):0){
      if(2^i <= num){
        num <- num - 2^i
        r[digits - i] <- 1
      }
    }
    return(r)
  }
  
  V <- matrix(0, 2^length(p), length(p)) # 組み合わせ
  pV <- numeric(2^length(p)) # 組み合わせの発生確率
  sV <- numeric(2^length(p)) # 戦略1の数
  for(i in 1:(2^length(p))){
    V[i, ] <- d2b(i-1, digits=length(p))
    pV[i] <- prod((0==V[i, ])*(1-p) + (1==V[i, ])*p)
    sV[i] <- sum(V[i, ])
  }
  tapply(pV, sV, sum) # 戦略1の数ごとの生起確率
}


######################
### 勝利確率の計算 ###
######################

calc_p_win <- function(p){
  p_win_sum <- 0

  # ぐー/ちょき/ぱーを出した他の参加者数ごとに計算していく
  for(num_of_nq in 0:length(p_others)){
  
    # ぐー/ちょき/ぱーで勝つ確率
    if(0==num_of_nq){
      # 自分だけぐー/ちょき/ぱーならば、確実に勝利
      p_win_nq <- 1
    }else{
      # あいこにならなければ、半分の確率で勝利
      p_win_nq <- (1 - p_even(num_of_nq + 1))/2
    }
  
    # きゅーで勝つ確率
    if(2>num_of_nq){
      # 一人がぐー/ちょき/ぱーならば、確実に敗北
      p_win_q <- 0
    } else {
      # あいこになれば、勝利
      p_win_q <- p_even(num_of_nq)
    }

    # 勝利確率
    p_win <- (1-p)*p_win_nq + p*p_win_q

    # ぐー/ちょき/ぱーで負ける確率
    if(0==num_of_nq){
      # 自分だけぐー/ちょき/ぱーならば、確実に負けない
      p_lose_nq <- 0
    }else{
      # あいこになれば敗北
      # あいこ以外でも半分の確率で敗北
      p_lose_nq <- p_even(num_of_nq + 1) + (1 - p_even(num_of_nq + 1))/2
    }
  
    # きゅーで負ける確率
    if(0 == num_of_nq){
      # 全員がきゅーならば、引き分けで負けない
      p_lose_q <- 0
    }else if(1 == num_of_nq){
      # 一人がぐー/ちょき/ぱーならば、確実に敗北
      p_lose_q <- 1
    }else{
      # あいこ以外ならば、敗北
      p_lose_q <- 1 - p_even(num_of_nq)
    }

    # 敗北確率
    p_lose <- (1-p)*p_lose_nq + p*p_lose_q

    # num_of_nqが生じる確率
    s <- as.character(length(p_others) - num_of_nq)
    p_num_of_nq <- dist[s][[1]]
    if(is.na(p_num_of_nq)){
      p_num_of_nq <- 0
    }

    # 期待値調整をして勝利確率を合計する(引き分けは分母から除く)
    p_win_sum <- p_win_sum + p_num_of_nq * p_win/(p_win+p_lose)
  
    if(debug){
      print(sprintf("num_of_nq_of_others: %d (%.3f) p_win_nq: %f p_win_q: %f p_win: %f p_lose_nq: %f p_lose_q: %f p_lose: %f", num_of_nq, p_num_of_nq, p_win_nq, p_win_q, p_win, p_lose_nq, p_lose_q, p_lose))
    }
  }
  p_win_sum
}


####################
### 均衡値の計算 ###
####################

# 拡張じゃんけん参加人数
n <- 5

# 初期値
p_all <- runif(n)

# n*10回ぐらい回せば収束するであろうと言う粗雑な方針
debug <- FALSE
for(c in 0:(n*10)){
  # 最適化前の状態
  print(sprintf("%.5f", p_all))

  # 最適化を行なうプレイヤー
  i <- (c %% n) + 1

  # 最適化を行なうi以外のプレイヤーのpを固定して、
  # キューを選択する人数の確率質量関数を作る
  p_others <- p_all[-i]
  dist <- mkdist(p_others)

  # 勝利確率の最大化を行なう
  r_optimize <- optimize(calc_p_win, c(0, 1), maximum=TRUE)
  p_all[i] <- r_optimize$maximum
}

print(sprintf("%.5f", p_all))
sprintf("最適反応の平均値: %.5f", mean(p_all))


#############################################################
# p_allから負ける人数の期待値を計算し、通常じゃんけんと比較 #
#############################################################
dist <- mkdist(p_all)
expected_num_of_looser <- 0
compared <- (1-p_even(length(p_all)))*length(p_all)/2
for(num_of_nq in 0:length(p_all)){

  s <- as.character(length(p_all) - num_of_nq)
  p_num_of_nq <- dist[s][[1]]

  t <- 0
  if(1<num_of_nq){
    if(1==num_of_nq){
      # 一人だけぐー/ちょき/ぱー
      t <- length(p_all) - 1
    } else {
      p_e <- p_even(num_of_nq)
      t <- p_e*num_of_nq + (1-p_e)*(num_of_nq/2 + length(p_all) - num_of_nq)
    }
    expected_num_of_looser <- expected_num_of_looser + p_num_of_nq*t
  }
}
sprintf("負ける人数の期待値 通常じゃんけん: %.5f 拡張じゃんけん: %.5f",compared, expected_num_of_looser)

多重共線性を出してみよう

観測数100ぐらいでも、誤差項の分散など次第では多重共線性が推定結果に影響を与える例を作ってみました。

多重共線性が無いケース

set.seed(2103)
n <- 100
x1 <- 0.3 * runif(n, min=0, max=10) + rnorm(n, sd=1)
x2 <- 0.7 * runif(n, min=0, max=10) + rnorm(n, sd=1)
cor(x1, x2) # 説明変数間は低い相関係数
e <- rnorm(n, sd=10)
y <- 1 + 2*x1 + 3*x2 + e
summary(lm(y ~ x1 + x2))

真のモデルにx2が無い場合に、x1とx2で推定してもそれらしい推定結果になります。

y <- 1 + 2*x1 + e
summary(lm(y ~ x1 + x2))

分散拡大係数(VIF)は1.02弱と小さいです。

1/(1-summary(lm(x1 ~ x2))$r.squared)

多重共線性があるケース

係数の大きさが変化して、有意性が無くなるケース。誤差項の分散は無いケースと同じ程度です。

set.seed(2103)
n <- 100
x <- runif(n, min=0, max=10)
x1 <- 0.3 * x + rnorm(n, sd=0.5)
x2 <- 0.7 * x + rnorm(n, sd=0.5)
cor(x1, x2) # 説明変数間の相関係数が高い
e <- rnorm(n, sd=10)
y <- 1 + 2*x1 + 3*x2 + e
summary(lm(y ~ x1 + x2))

真のモデルにx2が無い場合に、x1とx2で推定するとx1の有意性も消えます。

y <- 1 + 2*x1 + e
summary(lm(y ~ x1 + x2))

VIFは2.81強と大きくは無いですが、観測数が小さいため影響しています。

1/(1-summary(lm(x1 ~ x2))$r.squared)

拡張Dickey-Fuller検定を横断面方向に拡張する

同一のデータ生成プロセスを踏んでいる複数の系列 y1, y2, y3, … を、それぞれ個別に単位根検定にかけると、定常であるのに標本数が不足して単位根の棄却に失敗しがちになる一方、c(y1, y2, y3, …) と単純に接続して単位根検定した場合、接続面に断続が生じるため単位根を過って棄却する事になります。

代表的な単位根検定のDickey-Fuller検定と、それに系列相関やトレンド項の影響も考慮したADF 検定では、差分データを前期の水準データで回帰して、前期の水準データの係数の標準誤差をτ分布で評価します。具体的には単位根が疑われる系列 Y_tを、\epsilonを誤差項として、

 Y_t = \beta Y_{t-1} + \epsilon

と書き、以下のように差分 \Delta Y_tを説明する式に変形し、

 Y_t - Y_{t-1} = \beta Y_{t-1} - Y_{t-1} + \epsilon
 \Delta Y_t  = (\beta - 1) Y_{t-1} + \epsilon = \gamma Y_{t-1} + \epsilon

 \gamma = 0であるかを検定し、棄却されれば単位根が無いとします。ここで異なる系列でも同一のデータ生成プロセスであれば、前期の水準データ Y_{t-1}の係数 \gammaは同一となります。つまり、系列ごとに差分データと前期の水準データの組み合わせを作成後にデータを統合すれば、複数の系列を同時に単位根検定する事ができます。

一般に時系列方向と横断面方向にデータの広がりのあるパネルデータの場合、横断面方向にデータの広がりがあるため、単一系列の場合と異なり見せかけの相関が生じにくく、株価などの不確実性の高い高頻度取引などではなく、観察対象が低頻度に理屈を立てて行動した結果でああるため、単位根の存在は気にしない事が多い*1わけですが、たまたま稀な需要があったのでurcaパッケージのur.dfを拡張してみました。

1. ソースコード

urcaを呼び出したあと、関数ur.dfを上書きします。ちょっと長いですがデータ統合する部分以外は、元と同じです。ですから、元と同じオプションが使えます。元のが使いたくなった場合は、環境を指定するか、追加定義したグローバル領域のur.dfをrm(ur.df)して消してください。

library(urca)
ur.df <- function (..., type = c("none", "drift", "trend"), lags = 1, selectlags = c("Fixed", "AIC", "BIC"))
{
  lag <- as.integer(lags)
  if (lag < 0)
    stop("\nLags must be set to an non negative integer value.\n")
  lags <- lags + 1

  args <- list(...)
  len <- length(args)
  if(len <= 0)
    stop("\ny must be set.\n")
  tmp <- as.list(NULL)
  tmp[["n"]] <- 0

  for(i in 1:len){
    y <- args[[i]]
    y <- y[!is.na(y)]

    if (ncol(as.matrix(y)) > 1)
      stop("\ny is not a vector or univariate time series.\n")
    if (any(is.na(y)))
      stop("\nNAs in y.\n")

    y <- as.vector(y)
    z <- diff(y)
    n <- length(z)
    x <- embed(z, lags)
    z.diff <- x[, 1]
    z.lag.1 <- y[lags:n]

    tmp[["y"]] <- append(tmp[["y"]], y)
    tmp[["z"]] <- append(tmp[["z"]], z)
    tmp[["n"]] <- tmp[["n"]] + n
    tmp[["x"]] <- rbind(tmp[["x"]], x)
    tmp[["z.diff"]] <- append(tmp[["z.diff"]], z.diff)
    tmp[["z.lag.1"]] <- append(tmp[["z.lag.1"]], z.lag.1)
    tmp[["tt"]] <- append(tmp[["tt"]], lags:n)
  }

  y <- tmp[["y"]]
  z <- tmp[["z"]]
  n <- tmp[["n"]]
  x <- tmp[["x"]]
  z.diff <- tmp[["z.diff"]]
  z.lag.1 <- tmp[["z.lag.1"]]
  tt <- tmp[["tt"]]

  (n-length(z.lag.1)+1):n

  selectlags <- match.arg(selectlags)
  type <- match.arg(type)

  CALL <- match.call()
  DNAME <- deparse(substitute(y))
  x.name <- deparse(substitute(y))

  if (lags > 1) {
    if (selectlags != "Fixed") {
      critRes <- rep(NA, lags)
      for (i in 2:(lags)) {
        z.diff.lag = x[, 2:i]
        if (type == "none")
         result <- lm(z.diff ~ z.lag.1 - 1 + z.diff.lag)
        if (type == "drift")
         result <- lm(z.diff ~ z.lag.1 + 1 + z.diff.lag)
        if (type == "trend")
         result <- lm(z.diff ~ z.lag.1 + 1 + tt + z.diff.lag)
        critRes[i] <- AIC(result, k = switch(selectlags,
         AIC = 2, BIC = log(length(z.diff))))
      }
      lags <- which.min(critRes)
    }
    z.diff.lag = x[, 2:lags]
    if (type == "none") {
      result <- lm(z.diff ~ z.lag.1 - 1 + z.diff.lag)
      tau <- coef(summary(result))[1, 3]
      teststat <- as.matrix(tau)
      colnames(teststat) <- "tau1"
    }
    if (type == "drift") {
      result <- lm(z.diff ~ z.lag.1 + 1 + z.diff.lag)
      tau <- coef(summary(result))[2, 3]
      phi1.reg <- lm(z.diff ~ -1 + z.diff.lag)
      phi1 <- anova(phi1.reg, result)$F[2]
      teststat <- as.matrix(t(c(tau, phi1)))
      colnames(teststat) <- c("tau2", "phi1")
    }
    if (type == "trend") {
      result <- lm(z.diff ~ z.lag.1 + 1 + tt + z.diff.lag)
      tau <- coef(summary(result))[2, 3]
      phi2.reg <- lm(z.diff ~ -1 + z.diff.lag)
      phi3.reg <- lm(z.diff ~ z.diff.lag)
      phi2 <- anova(phi2.reg, result)$F[2]
      phi3 <- anova(phi3.reg, result)$F[2]
      teststat <- as.matrix(t(c(tau, phi2, phi3)))
      colnames(teststat) <- c("tau3", "phi2", "phi3")
    }
  }
  else {
    if (type == "none") {
      result <- lm(z.diff ~ z.lag.1 - 1)
      tau <- coef(summary(result))[1, 3]
      teststat <- as.matrix(tau)
      colnames(teststat) <- "tau1"
    }
    if (type == "drift") {
      result <- lm(z.diff ~ z.lag.1 + 1)
      phi1.reg <- lm(z.diff ~ -1)
      phi1 <- anova(phi1.reg, result)$F[2]
      tau <- coef(summary(result))[2, 3]
      teststat <- as.matrix(t(c(tau, phi1)))
      colnames(teststat) <- c("tau2", "phi1")
    }
    if (type == "trend") {
      result <- lm(z.diff ~ z.lag.1 + 1 + tt)
      phi2.reg <- lm(z.diff ~ -1)
      phi3.reg <- lm(z.diff ~ 1)
      phi2 <- anova(phi2.reg, result)$F[2]
      phi3 <- anova(phi3.reg, result)$F[2]
      tau <- coef(summary(result))[2, 3]
      teststat <- as.matrix(t(c(tau, phi2, phi3)))
      colnames(teststat) <- c("tau3", "phi2", "phi3")
    }
  }
  rownames(teststat) <- "statistic"
  testreg <- summary(result)
  res <- residuals(testreg)
  if (n < 25)
    rowselec <- 1
  if (25 <= n & n < 50)
    rowselec <- 2
  if (50 <= n & n < 100)
    rowselec <- 3
  if (100 <= n & n < 250)
    rowselec <- 4
  if (250 <= n & n < 500)
    rowselec <- 5
  if (n >= 500)
    rowselec <- 6
  if (type == "none") {
    cval.tau1 <- rbind(c(-2.66, -1.95, -1.6), c(-2.62, -1.95,
      -1.61), c(-2.6, -1.95, -1.61), c(-2.58, -1.95, -1.62),
      c(-2.58, -1.95, -1.62), c(-2.58, -1.95, -1.62))
    cvals <- t(cval.tau1[rowselec, ])
    testnames <- "tau1"
  }
  if (type == "drift") {
    cval.tau2 <- rbind(c(-3.75, -3, -2.63), c(-3.58, -2.93,
      -2.6), c(-3.51, -2.89, -2.58), c(-3.46, -2.88, -2.57),
      c(-3.44, -2.87, -2.57), c(-3.43, -2.86, -2.57))
    cval.phi1 <- rbind(c(7.88, 5.18, 4.12), c(7.06, 4.86,
      3.94), c(6.7, 4.71, 3.86), c(6.52, 4.63, 3.81), c(6.47,
      4.61, 3.79), c(6.43, 4.59, 3.78))
    cvals <- rbind(cval.tau2[rowselec, ], cval.phi1[rowselec,
      ])
    testnames <- c("tau2", "phi1")
  }
  if (type == "trend") {
    cval.tau3 <- rbind(c(-4.38, -3.6, -3.24), c(-4.15, -3.5,
      -3.18), c(-4.04, -3.45, -3.15), c(-3.99, -3.43, -3.13),
      c(-3.98, -3.42, -3.13), c(-3.96, -3.41, -3.12))
    cval.phi2 <- rbind(c(8.21, 5.68, 4.67), c(7.02, 5.13,
      4.31), c(6.5, 4.88, 4.16), c(6.22, 4.75, 4.07), c(6.15,
      4.71, 4.05), c(6.09, 4.68, 4.03))
    cval.phi3 <- rbind(c(10.61, 7.24, 5.91), c(9.31, 6.73,
      5.61), c(8.73, 6.49, 5.47), c(8.43, 6.49, 5.47),
      c(8.34, 6.3, 5.36), c(8.27, 6.25, 5.34))
    cvals <- rbind(cval.tau3[rowselec, ], cval.phi2[rowselec,
      ], cval.phi3[rowselec, ])
    testnames <- c("tau3", "phi2", "phi3")
  }
  colnames(cvals) <- c("1pct", "5pct", "10pct")
  rownames(cvals) <- testnames
  new("ur.df", y = y, model = type, cval = cvals, lags = lag,
    teststat = teststat, testreg = testreg, res = res, test.name = "Augmented Dickey-Fuller Test")
}

2. 使い方

多少はと言った程度ですが、個別に単位根検定をかけるよりは、系列をまとめて検定する方が正しくなります。

genS <- function(n=200, beta=1.0){
  x <- numeric(n)
  x[1] <- 0
  for(i in 2:n){
    x[i] <- beta*x[i-1] + rnorm(1)
  }
  x
}

set.seed(121) # 数字を固定しないと結果はマチマチ
y1 <- genS(30) # 非定常過程を生成
y2 <- genS(30)
y3 <- genS(30)
summary(ur.df(c(y1, y2, y3))) # 単位根を過って棄却する
summary(ur.df(y1, y2, y3)) # 単位根を棄却しない

set.seed(100) # 数字を固定しないと結果はマチマチ
y4 <- genS(30, 0.9) # 定常過程を生成
y5 <- genS(30, 0.9)
y6 <- genS(30, 0.9)
summary(ur.df(y4)) # 単位根を棄却しない
summary(ur.df(y5)) # 単位根を棄却しない
summary(ur.df(y6)) # 単位根を棄却しない
summary(ur.df(y4, y5, y6)) # 単位根を棄却する

*1: 同時性、不均一分散、系列相関はとても気にされる。