我有一個優化問題,Nelder-Mead
方法將解決,但我也想用BFGS
或Newton-Raphson解決,或採取某些措施一個梯度函數,更快的速度,並希望更精確的估計。我在optim
/optimx
文檔中編寫了這樣一個漸變函數,但是當我將它與BFGS
一起使用時,我的起始值不會移動(optim()
),否則函數徹底不能運行(optimx()
,它返回Error: Gradient function might be wrong - check it!
)。對不起,有一些代碼涉及再現這一點,但這裏有:如何指定梯度函數以用於optim()或其他優化器
這是我想獲得參數估計的函數(這是爲了平滑老年死亡率,其中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)
}
輸出是一個長度爲2的向量,相對於p的變化參數a
和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
元素,它說,被稱爲31次,Kannisto.gr()
只有1次。 $convergence
是0
,所以我想它認爲它收斂了(如果我給予不太合理的開始,他們也保持放置)。我減少了寬容等,沒有任何變化。當我在optimx()
(未顯示)嘗試同樣的呼叫時,我收到上面提到的戰鬥,並且沒有任何對象返回。指定gr = Kannisto.gr
與"CG"
時,我會得到相同的結果。隨着"L-BFGS-B"
方法我會得到相同的初始值追溯到估計,但也有報道,這兩個函數和梯度被稱爲21次,並有一條錯誤消息: "ERROR: BNORMAL_TERMINATION_IN_LNSRCH"
我希望有一些稍微詳細一點的梯度函數的寫法,將解決這個問題,因爲這個後來的警告和optimx
行爲都直言不諱地暗示該函數根本不對(我認爲)。我也嘗試了maxLik
包中的maxNR()
最大化器,並觀察到類似的行爲(起始值不移動)。任何人都可以給我一個指針?非常感謝
[編輯] @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
按照文森特的回答,我重新調整了梯度功能,並使用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
這是解決速度遠遠超過我所期待的,我學到比一些技巧了。感謝文森特!
要檢查您的漸變是否正確,可以使用數字近似進行比較,例如'library(numDeriv); (函數(u)KannistoLik1(c(a = u [1],b = u [2]),.Dx,.Exp),c(1,1)); Kannisto.gr(c(a = 1,b = 1),.Dx,.Exp)'。這些標誌是錯誤的:算法在朝這個方向移動時看不到任何改進,因此不會移動。 – 2012-07-24 01:57:21
謝謝文森特。試了一下,會發布結果上面 – 2012-07-24 02:04:15