R中Nelder-Mead优化(fminbnd)报错问题求助
优化二元选择Softmax似然函数时的
missing value where TRUE/FALSE needed错误解决 报错详情
运行neldermead包的fminbnd优化自定义似然函数时,触发以下错误:
Error in if (fr < fhigh) { : missing value where TRUE/FALSE needed
开启verbose模式后,报错前的关键输出:
Step #1 : order ================================================================= Iteration #1 (total = 1) Function Eval #2 Xopt: [0.04] Fopt: 1.100429e+02 DeltaFv: Inf Center: [2.85944413880818] Size: 5.638888e+00 Vertex #1/2 : fv=1.100429e+02, x=4.000000e-02 Vertex #2/2 : fv=Inf, x=5.678888e+00 Reflect xbar=[0.04] boxlinesearch > xhigh=[5.67888827761635], fhigh=Inf > xbar=[0.04] > xr = [-7.29055476090126] Function Evaluation #3 at [-7.29055476090126 ]
自定义优化函数
目标函数基于二元选择试验计算似然值,用于拟合Softmax决策策略:
softmaxEV <- function(startphi){ pL <- c() for (row in 1:nrow(oneDat)){ VA= oneDat[row, "EVA"] VB= oneDat[row, "EVB"] if (oneDat[row, "response"] == 0){ p= exp(startphi*VA)/(exp(startphi*VA)+exp(startphi*VB)) pL <-append(pL,p) } else { p= 1- (exp(startphi*VA)/(exp(startphi*VA)+exp(startphi*VB))) pL <-append(pL,p) } } gEV <- -2*sum(log(pL)) return(gEV) }
优化调用代码
函数嵌入参与者遍历循环中,设置参数范围为0到10:
optRes <- fminbnd(softmaxEV, startphi,0,10, verbose= TRUE)
已尝试的无效方案
- 移除边界改用
fminsearch - 调整边界范围
- 切换到pracma包的
fminbnd - 转至Python使用
minimize函数 - 手动测试多个
startphi值(未触发报错)
问题根源
- 数值溢出/下溢:当优化算法生成的
startphi值过大(如5.67)或超出边界(如-7.29)时,exp(startphi*VA)或exp(startphi*VB)可能溢出到Inf或下溢到0,导致:Inf/Inf得到NaN,使得p为NaNlog(0)得到-Inf,累加后导致gEV为Inf或NaN
- 参数越界:优化算法可能跳出设定的[0,10]范围,进入无意义的参数区间,触发无效计算。
- 循环效率问题:逐行循环拼接向量容易引入隐性错误,且数值稳定性差。
解决方法
1. 稳定Softmax计算(避免数值溢出)
使用log-sum-exp技巧重新实现似然计算,避免直接计算大指数:
softmaxEV_stable <- function(startphi){ # 向量化计算,替代循环 VA <- oneDat$EVA VB <- oneDat$EVB response <- oneDat$response # 计算稳定的log(softmax) max_val <- pmax(startphi*VA, startphi*VB) log_denom <- max_val + log(exp(startphi*VA - max_val) + exp(startphi*VB - max_val)) log_pA <- startphi*VA - log_denom # 根据response计算log似然 log_pL <- ifelse(response == 0, log_pA, log(1 - exp(log_pA))) # 处理极端情况(如log_pA为-Inf时,1-exp(log_pA)=1,log(1)=0) log_pL <- ifelse(is.infinite(log_pA) & response == 1, 0, log_pL) gEV <- -2*sum(log_pL, na.rm = TRUE) return(gEV) }
2. 限制参数范围
在函数开头添加参数检查,对超出[0,10]的参数返回极大惩罚值,避免无效计算:
softmaxEV_stable <- function(startphi){ # 参数越界惩罚 if (startphi < 0 || startphi > 10) { return(1e10) } # 后续稳定计算代码... }
3. 优化算法选择
使用支持边界约束的优化函数,如stats::optim(method="L-BFGS-B"),确保参数不会越界:
optRes <- optim(par = startphi, fn = softmaxEV_stable, method = "L-BFGS-B", lower = 0, upper = 10)
验证
替换函数后重新运行优化,即可避免Inf/NaN导致的条件判断错误,同时提升计算效率和稳定性。
内容的提问来源于stack exchange,提问作者Rox
相关产品推荐
相关产品推荐

