この方法で解決できる最適化問題がありますが、ニュートンラプソン法、または勾配関数をNelder-Mead
使用するものを使用して、より高速に、できればより正確な推定を行うために解決したいと思います。/ドキュメントBFGS
の例に従ってこのようなグラデーション関数を作成しましたが、開始値で使用すると、移動しない()か、関数が完全に実行されません(、を返します)。これを再現するために少しコードが含まれていることをお詫びしますが、ここに行きます:optim
optimx
BFGS
optim()
optimx()
Error: Gradient function might be wrong - check it!
これは、パラメーター推定値を取得したい関数です(これは、老齢死亡率を平滑化するためのものです。ここで、xは年齢で、80歳から始まります)。
KannistoMu <- function(pars, x = .5:30.5){
a <- pars["a"]
b <- pars["b"]
(a * exp(b * x)) / (1 + a * exp(b * x))
}
そして、これが観察された率(死亡、.Dx
過剰曝露として定義される.Exp
)からそれを推定するための対数尤度関数です:
KannistoLik1 <- function(pars, .Dx, .Exp, .x. = .5:30.5){
mu <- KannistoMu(exp(pars), x = .x.)
# take negative and minimize it (default optimizer behavior)
-sum(.Dx * log(mu) - .Exp * mu, na.rm = TRUE)
}
ファイナルを制約し、ポジティブになるために、私が最適化するexp(pars)
ために与えるので、あなたはそこに見えます。log(pars)
a
b
データ例(1962年の日本の女性、興味があれば):
.Dx <- structure(c(10036.12, 9629.12, 8810.11, 8556.1, 7593.1, 6975.08,
6045.08, 4980.06, 4246.06, 3334.04, 2416.03, 1676.02, 1327.02,
980.02, 709, 432, 350, 217, 134, 56, 24, 21, 10, 8, 3, 1, 2,
1, 0, 0, 0), .Names = c("80", "81", "82", "83", "84", "85", "86",
"87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97",
"98", "99", "100", "101", "102", "103", "104", "105", "106",
"107", "108", "109", "110"))
.Exp <- structure(c(85476.0333333333, 74002.0866666667, 63027.5183333333,
53756.8983333333, 44270.9, 36749.85, 29024.9333333333, 21811.07,
16912.315, 11917.9583333333, 7899.33833333333, 5417.67, 3743.67833333333,
2722.435, 1758.95, 1043.985, 705.49, 443.818333333333, 223.828333333333,
93.8233333333333, 53.1566666666667, 27.3333333333333, 16.1666666666667,
10.5, 4.33333333333333, 3.16666666666667, 3, 2.16666666666667,
1.5, 0, 1), .Names = c("80", "81", "82", "83", "84", "85", "86",
"87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97",
"98", "99", "100", "101", "102", "103", "104", "105", "106",
"107", "108", "109", "110"))
Nelder-Mead
このメソッドでは、次のように機能します。
NMab <- optim(log(c(a = .1, b = .1)),
fn = KannistoLik1, method = "Nelder-Mead",
.Dx = .Dx, .Exp = .Exp)
exp(NMab$par)
# these are reasonable estimates
a b
0.1243144 0.1163926
これは私が思いついた勾配関数です:
Kannisto.gr <- function(pars, .Dx, .Exp, x = .5:30.5){
a <- exp(pars["a"])
b <- exp(pars["b"])
d.a <- (a * exp(b * x) * .Exp + (-a * exp(b * x) - 1) * .Dx) /
(a ^ 3 * exp(2 * b * x) + 2 * a ^ 2 * exp(b * x) + a)
d.b <- (a * x * exp(b * x) * .Exp + (-a * x * exp(b * x) - x) * .Dx) /
(a ^ 2 * exp(2 * b * x) + 2 * a * exp(b * x) + 1)
-colSums(cbind(a = d.a, b = d.b), na.rm = TRUE)
}
a
出力は長さ2のベクトルであり、パラメーターと。に関する変化b
です。また、の出力を利用して醜いバージョンに到達しましたderiv()
。これは同じ答えを返し、投稿しません(導関数が正しいことを確認するためだけに)。
optim()
次のように指定するBFGS
と、メソッドとして、推定値は開始値から移動しません。
BFGSab <- optim(log(c(a = .1, b = .1)),
fn = KannistoLik1, gr = Kannisto.gr, method = "BFGS",
.Dx = .Dx, .Exp = .Exp)
# estimates do not change from starting values:
exp(BFGSab$par)
a b
0.1 0.1
$counts
出力の要素を見ると、KannistoLik1()
31回とKannisto.gr()
1回だけ呼び出されたことがわかります。$convergence
である0
ため、収束したと思います(あまり合理的でないスタートを与えると、それらもそのままになります)。公差などを減らしても何も変わりません。同じ呼び出しを試みた場合optimx()
(図には示されていません)、上記の警告を受け取り、オブジェクトは返されません。gr = Kannisto.gr
で指定しても同じ結果が得られます"CG"
。この"L-BFGS-B"
方法では、推定と同じ開始値が返されますが、関数と勾配の両方が21回呼び出され、エラーメッセージが表示されることも報告されています。
"ERROR: BNORMAL_TERMINATION_IN_LNSRCH"
optimx
この後の警告と動作は、関数が単に正しくないことを率直に示唆しているため、これを解決する勾配関数の記述方法に若干の詳細があることを期待しています(私は思います)。maxNR()
また、パッケージからマキシマイザーを試し、maxLik
同様の動作を観察しました(開始値は移動しません)。誰かが私にポインタを与えることができますか?とても感謝しております
[編集]@Vincentは、数値近似からの出力と比較することを提案しました。
library(numDeriv)
grad( function(u) KannistoLik1( c(a=u[1], b=u[2]), .Dx, .Exp ), log(c(.1,.1)) )
[1] -14477.40 -7458.34
Kannisto.gr(log(c(a=.1,b=.1)), .Dx, .Exp)
a b
144774.0 74583.4
とても異なるサイン、そして10倍オフ?それに合わせて勾配関数を変更します。
Kannisto.gr2 <- function(pars, .Dx, .Exp, x = .5:30.5){
a <- exp(pars["a"])
b <- exp(pars["b"])
d.a <- (a * exp(b * x) * .Exp + (-a * exp(b * x) - 1) * .Dx) /
(a ^ 3 * exp(2 * b * x) + 2 * a ^ 2 * exp(b * x) + a)
d.b <- (a * x * exp(b * x) * .Exp + (-a * x * exp(b * x) - x) * .Dx) /
(a ^ 2 * exp(2 * b * x) + 2 * a * exp(b * x) + 1)
colSums(cbind(a=d.a,b=d.b), na.rm = TRUE) / 10
}
Kannisto.gr2(log(c(a=.1,b=.1)), .Dx, .Exp)
# same as numerical:
a b
-14477.40 -7458.34
オプティマイザーで試してみてください。
BFGSab <- optim(log(c(a = .1, b = .1)),
fn = KannistoLik1, gr = Kannisto.gr2, method = "BFGS",
.Dx = .Dx, .Exp = .Exp)
# not reasonable results:
exp(BFGSab$par)
a b
Inf Inf
# and in fact, when not exp()'d, they look oddly familiar:
BFGSab$par
a b
-14477.40 -7458.34
Vincentの答えに従って、勾配関数を再スケーリングし、パラメーターを正に保つabs()
代わりに使用しました。exp()
最新の、よりパフォーマンスの高い目的関数と勾配関数:
KannistoLik2 <- function(pars, .Dx, .Exp, .x. = .5:30.5){
mu <- KannistoMu.c(abs(pars), x = .x.)
# take negative and minimize it (default optimizer behavior)
-sum(.Dx * log(mu) - .Exp * mu, na.rm = TRUE)
}
# gradient, to be down-scaled in `optim()` call
Kannisto.gr3 <- function(pars, .Dx, .Exp, x = .5:30.5){
a <- abs(pars["a"])
b <- abs(pars["b"])
d.a <- (a * exp(b * x) * .Exp + (-a * exp(b * x) - 1) * .Dx) /
(a ^ 3 * exp(2 * b * x) + 2 * a ^ 2 * exp(b * x) + a)
d.b <- (a * x * exp(b * x) * .Exp + (-a * x * exp(b * x) - x) * .Dx) /
(a ^ 2 * exp(2 * b * x) + 2 * a * exp(b * x) + 1)
colSums(cbind(a = d.a, b = d.b), na.rm = TRUE)
}
# try it out:
BFGSab2 <- optim(
c(a = .1, b = .1),
fn = KannistoLik2,
gr = function(...) Kannisto.gr3(...) * 1e-7,
method = "BFGS",
.Dx = .Dx, .Exp = .Exp
)
# reasonable:
BFGSab2$par
a b
0.1243249 0.1163924
# better:
KannistoLik2(exp(NMab1$par),.Dx = .Dx, .Exp = .Exp) > KannistoLik2(BFGSab2$par,.Dx = .Dx, .Exp = .Exp)
[1] TRUE
これは私が予想していたよりもはるかに速く解決され、私はいくつかのトリック以上を学びました。ヴィンセントありがとう!