R中optimx报错:无法在初始参数处评估函数求助
解决optimx无法评估初始参数的问题(Lee-Carter模型参数估计)
你的报错核心原因是计算链完全断裂:calculate_error函数直接调用convert2时,Lx、lx等关键中间变量从未生成,导致R无法在初始参数处计算函数值。以下是代码中的关键错误及修正方案:
关键问题梳理
- 计算流程缺失:
calculate_error跳过了从kt到mx、qx、lx、dx、Lx的完整推导步骤,直接调用最终转换函数,导致变量未定义。 - 函数参数冗余/未定义:多个辅助函数存在无效参数(如
convert1的mx、qx),或引用了函数外部未定义的变量(如calculate_dx中的l0)。 - 循环与公式错误:
calculate_lx的循环逻辑重复赋值,calculate_Lx的公式不符合预期寿命推导逻辑,且循环语法有误。 - 初始参数不合理:Lee-Carter模型中
kt通常是中心化数值(均值接近0),你给出的初始值接近预期寿命,可能导致优化难以收敛。
修正后的完整代码
# 简化的ax和bx矩阵 ax <- c(-4.3198094, -5.8995814, -6.1240039, -7.0870399, -7.0525417) bx <- c(0.04522097, 0.02488256, 0.02452534, -3.2110186, -3.0955417) data <- data.frame( DATE = as.Date(c("2019-01-01", "2020-01-01", "2021-01-01", "2022-01-01", "2023-01-01")), LE = c(77.76000, 77.05507, 76.34821, 75.64329, 74.93836) ) e0_expert <- data$LE # 从kt计算mx并转换为qx(移除冗余参数) mx_to_qx <- function(ax, bx, kt) { mx <- exp(ax + kt * bx) # 死亡均匀分布假设下的qx近似,限制qx不超过1避免负数lx qx <- pmin((2 * mx) / (2 + mx), 0.9999) return(qx) } # 从qx计算lx(修正循环逻辑) calculate_lx <- function(qx, l0 = 10000) { n <- length(qx) lx <- numeric(n + 1) # lx长度比qx多1(l0到ln) lx[1] <- l0 for (i in 1:n) { lx[i + 1] <- lx[i] * (1 - qx[i]) } return(lx) } # 从lx计算dx(移除冗余参数,修复未定义变量) calculate_dx <- function(lx) { n <- length(lx) - 1 dx <- numeric(n) for (i in 1:n) { dx[i] <- lx[i] - lx[i + 1] } return(dx) } # 从lx和dx计算Lx(修正公式与循环语法) calculate_Lx <- function(lx, dx) { n <- length(dx) Lx <- numeric(n) # 0岁组特殊处理(死亡集中在前半年) Lx[1] <- lx[2] + 0.5 * dx[1] # 其他年龄组使用死亡均匀分布假设 for (i in 2:n) { Lx[i] <- (lx[i] + lx[i + 1]) / 2 } # 最后一个年龄组Lx(假设寿命极限,简化为lx[n+1]/0.001) Lx[n] <- lx[n + 1] / 0.001 return(Lx) } # 从Lx和lx计算出生预期寿命e0(移除冗余参数) Lx_to_e0 <- function(Lx, lx) { Tx <- rev(cumsum(rev(Lx))) # 计算剩余寿命总和Tx ex <- Tx / lx[1:length(Tx)] # 预期寿命ex = Tx/lx return(ex[1]) # 返回出生预期寿命e0 } # 误差计算函数(补全完整计算链) calculate_error <- function(kt, e0_expert, ax, bx) { if (length(kt) != length(e0_expert)) { stop("kt长度必须与e0_expert一致") } total_error <- 0 for (t in 1:length(kt)) { # 完整推导链:kt -> qx -> lx -> dx -> Lx -> e0 qx <- mx_to_qx(ax, bx, kt[t]) lx <- calculate_lx(qx) dx <- calculate_dx(lx) Lx <- calculate_Lx(lx, dx) e0_est <- Lx_to_e0(Lx, lx) total_error <- total_error + (e0_est - e0_expert[t])^2 } cat("当前误差平方和:", total_error, "\n") return(total_error) } # 使用符合Lee-Carter特性的初始kt(中心化,均值为0) initial_kt <- rep(0, length(e0_expert)) # 运行optimx优化 library(optimx) result <- optimx( par = initial_kt, fn = calculate_error, e0_expert = e0_expert, ax = ax, bx = bx, method = "Nelder-Mead", control = list(trace = 1, maxit = 1000, abstol = 1e-6, minimize = TRUE) ) # 输出最优kt optimal_kt <- result$par cat("最优kt值:", optimal_kt, "\n")
修正说明
- 补全计算链:在
calculate_error中实现了从kt到e0的完整推导,确保所有中间变量都被正确生成。 - 优化函数设计:移除冗余参数,每个函数仅接收必要输入,避免引用外部未定义变量。
- 修复逻辑错误:调整循环逻辑,修正
Lx的计算方法(符合预期寿命的标准推导),并处理边界情况。 - 调整初始参数:将
kt初始值设为均值0的向量,匹配Lee-Carter模型的参数特性,帮助优化收敛。
内容的提问来源于stack exchange,提问作者Cassiopea
相关产品推荐
相关产品推荐

