北川先生の本「Rによる 時系列モデリング入門」で,Householder変換を使った最小2乗フィットの話が登場したので,Rでやってみます.
ここでは,以下の式を使ってデータを生成します.
ここで,は,平均0,標準偏差
sd.eps
の正規乱数とします.
以下のスクリプトでは,データの長さをN
,パラメタを
a1
,を
a2
に設定します.
と表せば,
です.ベクトルはすべて縦書きの列ベクトルとします.
逆行列を使った最小2乗法
残差としてのの2乗和が最小になるように
を計算すると,
となります.は,
の転置行列を表します.説明は,過去の記事を参考にしてください.
chaos-kiyono.hatenablog.com
以下は,N = 10
,a1 = 2.4
,a2 = -3.0
とした例です.Rのコマンドを使って逆行列を計算して,パラメタを推定しています.
# データの長さ N <- 10 # 誤差の標準偏差 sd.eps <- 1 eps <- rnorm(N,0,sd.eps) ############################## a1 <- 2.4 a2 <- -3.0 ############################## # 真のモデルは # y[i] = a1 * x1[i] + a2 * x2[i] + eps[i] ############################## x1 <- rnorm(N,0,1) x2 <- rnorm(N,0,1) y <- a1*x1+a2*x2+eps ############################## Y <- matrix(y[1:N], ncol=1) # ncolで列数のみ指定 Z <- matrix(c(x1[1:N],x2[1:N]), ncol=2) ############################## # a.hat = (t(Z) Z)^{-1} t(Z) Y ############################## a.hat <- solve(t(Z) %*% Z) %*% (t(Z) %*% Y) # 残差の2乗平均 sig2.hat <- sum((Y - Z %*% a.hat)^2)/nrow(Y) # a1, a2の推定結果 a.hat[,1] # 残差の2乗平均 sig2 sig2.hat
このスクリプトを実行すると,
> # a1, a2の推定結果 > a.hat[,1] [1] 2.425303 -3.634048 > # 残差の2乗平均 sig2 > sig2.hat [1] 1.607804
のように,パラメタと残差が計算されます.
QR分解 (Householder変換)を使った最小2乗法
次は,QR分解 (Householder変換)でパラメタを推定してみます.pracma
パッケージを使いました.最初に,このパッケージをインストールしてください.
使ったRスクリプトは以下です.
#install.packages("pracma") require(pracma) # データの長さ N <- 10 # 誤差の標準偏差 sd.eps <- 1 eps <- rnorm(N,0,sd.eps) ############################## a1 <- 2.4 a2 <- -3.0 ############################## # 真のモデルは # y[i] = a1 * x1[i] + a2 * x2[i] + eps[i] ############################## x1 <- rnorm(N,0,1) x2 <- rnorm(N,0,1) y <- a1*x1+a2*x2+eps ############################## Y <- matrix(y[1:N], ncol=1) # ncolで列数のみ指定 Z <- matrix(c(x1[1:N],x2[1:N]), ncol=2) ### # X = [Z|Y] と結合 X <- cbind(Z,Y) ############################## # Householder変換 UX <- householder(X)$R ### m <- ncol(UX)-1 a.hat <- numeric(m) a.hat[m] <- UX[m,m+1]/UX[m,m] for(i in 2:m){ a.hat[m+1-i] <- (UX[m+1-i,m+1]-a.hat[(m+2-i):m] %*% UX[m+1-i,((m+2-i)):m])/UX[m+1-i,m+1-i] } # 残差の2乗平均 sig2.hat <- UX[3,3]^2/nrow(Y) # a1, a2の推定結果 a.hat # 残差の2乗平均 sig2 sig2.hat
このスクリプトを実行すると,
> # a1, a2の推定結果 > a.hat [1] 2.611575 -2.950162 > # 残差の2乗平均 sig2 > sig2.hat [1] 0.6768868
のように,パラメタと残差が計算されます.
pracma
パッケージを使わなくても,Rのコマンドqr
を使えば,QR分解できます.中身のアルゴリズムについては,何を使っているのか分かりません.Rスクリプトは以下です.
# データの長さ N <- 10 # 誤差の標準偏差 sd.eps <- 1 eps <- rnorm(N,0,sd.eps) ############################## a1 <- 2.4 a2 <- -3.0 ############################## # 真のモデルは # y[i] = a1 * x1[i] + a2 * x2[i] + eps[i] ############################## x1 <- rnorm(N,0,1) x2 <- rnorm(N,0,1) y <- a1*x1+a2*x2+eps ############################## Y <- matrix(y[1:N], ncol=1) # ncolで列数のみ指定 Z <- matrix(c(x1[1:N],x2[1:N]), ncol=2) ### # X = [Z|Y] と結合 X <- cbind(Z,Y) ############################## # QR分解でRを求める UX <- qr.R(qr(X)) ### m <- ncol(UX)-1 a.hat <- numeric(m) a.hat[m] <- UX[m,m+1]/UX[m,m] for(i in 2:m){ a.hat[m+1-i] <- (UX[m+1-i,m+1]-a.hat[(m+2-i):m] %*% UX[m+1-i,((m+2-i)):m])/UX[m+1-i,m+1-i] } # 残差の2乗平均 sig2.hat <- UX[3,3]^2/nrow(Y) # a1, a2の推定結果 a.hat # 残差の2乗平均 sig2 sig2.hat
【付録】3変数の場合
逆行列を使う場合.
N <- 10 sig2 <- 1 eps <- rnorm(N,0,sqrt(sig2)) ############################## a1 <- 2.4 a2 <- -3.0 a3 <- -1.8 ############################## # 真のモデルは # y[i] = a1 * x1[i] + a2 * x2[i] + a3 * x3[i] + eps[i] ############################## x1 <- rnorm(N,0,1) x2 <- rnorm(N,0,1) x3 <- rnorm(N,0,1) y <- a1*x1+a2*x2+a3*x3+eps ############################## Y <- matrix(y[1:N], ncol=1) # ncolで列数のみ指定 Z <- matrix(c(x1[1:N],x2[1:N],x3[1:N]), ncol=3) ############################## # a.hat = (t(Z) Z)^{-1} t(Z) Y ############################## a.hat <- solve(t(Z) %*% Z) %*% (t(Z) %*% Y) # 残差の2乗平均 sig2.hat <- sum((Y - Z %*% a.hat)^2)/nrow(Y) # a1, a2の推定結果 a.hat[,1] # 残差の2乗平均 sig2 sig2.hat
Householder変換を使う場合.
#install.packages("pracma") require(pracma) ############### N <- 10 sig2 <- 1 eps <- rnorm(N,0,sqrt(sig2)) ############################## a1 <- 2.4 a2 <- -3.0 a3 <- -1.8 ############################## # 真のモデルは # y[i] = a1 * x1[i] + a2 * x2[i] + a3 * x3[i] + eps[i] ############################## x1 <- rnorm(N,0,1) x2 <- rnorm(N,0,1) x3 <- rnorm(N,0,1) y <- a1*x1+a2*x2+a3*x3+eps ############################## Y <- matrix(y[1:N], ncol=1) # ncolで列数のみ指定 Z <- matrix(c(x1[1:N],x2[1:N],x3[1:N]), ncol=3) ############################## # X = [Z|Y] と結合 X <- cbind(Z,Y) ############################## # Householder変換 UX <- householder(X)$R ### m <- ncol(UX)-1 a.hat <- numeric(m) a.hat[m] <- UX[m,m+1]/UX[m,m] for(i in 2:m){ a.hat[m+1-i] <- (UX[m+1-i,m+1]-a.hat[(m+2-i):m] %*% UX[m+1-i,((m+2-i)):m])/UX[m+1-i,m+1-i] } # 残差の2乗平均 sig2.hat <- UX[3,3]^2/nrow(Y) # a1, a2の推定結果 a.hat # 残差の2乗平均 sig2 sig2.hat