#
# n: 観測数, sd: 標準偏差, hg: 不均一分散(TRUE/FALSE)
# model: 真のモデルの数式表記
# return: x, y, zの観測値
#
setup <- function(n=100, sd=1, hg=FALSE, model=parse(text="1+2*x-3*y")){
x <- runif(n, 1, 3) # xの真の値
y <- runif(n, 1, 2) # yの真の値
u <- rnorm(n, sd=sd) # yの観測誤差
oy <- y + u # yの観測値
e <- rnorm(n, sd=sd) # xの観測誤差
# 不均一分散のときは上書き
if(hg){
for(i in 1:n){
e[i] <- rnorm(1, sd=max(1e-6, sd*y[i])) # 標準偏差は0より僅かに正にする
}
}
ox <- x + e # xの観測値
# 被説明変数zは真の値に従う
z <- eval(model)
data.frame(x = ox, y = oy, z=z)
}
#
# シミュレーションで比較してプロット
# n: 観測数, min_sd: 標準偏差の最小値, max_sd: 標準偏差の最大値
# hg: TRUEならば不均一分散を入れる(未使用)
# model: 真のモデルのテキスト表記
# plegend: 凡例の位置
#
compare <- function(n=100, min_sd=1e-06, max_sd=1, hg=FALSE, model="1+2*x-3*y", plegend="topright"){
len <- 100
compared <- data.frame(sd=numeric(len), non_divided=numeric(len), divided=numeric(len), nd_sw_test=numeric(len), d_sw_test=numeric(len), t_test=integer(len))
compared$sd <- seq(max(1e-06, min_sd), max_sd, length.out=len)
for(i in 1:len){
df <- setup(n=n, sd=compared$sd[i], hg=hg, model=parse(text=model))
# ベタベタな分岐
if(model=="1+2*x-3*y"){
# 普通に推定
r <- lm(z ~ x + y, data=df)
# 割り算推定
z_p_oy <- df$z/df$y
x_p_oy <- df$x/df$y
c_p_oy <- 1/df$y
r_p_oy <- lm(z_p_oy ~ x_p_oy + c_p_oy)
}else{
# 割り算あり
yz = df$z*df$y
r <- lm(yz ~ y + x + 0, data=df)
# 割り算なし
x_p_oy <- df$x/df$y
r_p_oy <- lm(df$z ~ x_p_oy)
}
# 切片項
compared$non_divided[i] <- coef(r)[2]
compared$divided[i] <- coef(r_p_oy)[2]
# 正規性の検定結果
compared$nd_sw_test[i] <- shapiro.test(residuals(r))$p.value
compared$d_sw_test[i] <- shapiro.test(residuals(r_p_oy))$p.value
# 95%信頼区間に2.0が含まれるか
compared$t_test[i] <- ifelse(abs(2.0 - coef(r)[2])<coef(summary(r))[, 2][2]*qt(1-0.05/2, r$df.residual), 1, 0)
}
# ylim <- c(min(compared$non_divided, compared$divided), max(compared$non_divided, compared$divided))
ylim <- c(0, 4)
plot(non_divided ~ sd, data=compared, xlim=c(min_sd, max_sd), ylim=ylim, type="l", main=sprintf("観測データ同士の割り算の影響\n観測数:%d%s", n, ifelse(hg,",不均一分散あり","")), xlab=sprintf("xとyの観測誤差の標準偏差%s", ifelse(hg, "(y=1のとき)", "")), ylab=parse(text = "beta[1]"))
lines(compared$sd, compared$divided, lty=2)
abline(h=2, col="red", lty=3)
# ある程度の信頼性の推定値を出した最大の標準偏差
rsd <- max(subset(compared, t_test==1)$sd)
abline(v=rsd, col="blue", lty=4)
text(rsd, 0, "推定値の95%信頼区間に2が入る限界線", col="blue", adj=c(0, 0))
legend(plegend, lty=c(1, 2, 3), pch=-1, legend=c("割り算なし", "割り算あり", "真の値"), col=c("black","black","red"), bty="n")
return(compared)
}
# 第1節のグラフ
set.seed(201408)
rd <- compare(max_sd=0.5, n=1000)
# 第2節のグラフ
set.seed(201408)
rd <- compare(max_sd=0.5, n=1000, model="1+2*(x/y)")