我想要在R中求解一个具有两个非线性约束的非线性目标函数.我已经在GAMS中成功地解决了该模型,但由于我的一般数据工作流,我想使用R来代替.该模型背后的 idea 是,我希望校准一个有理函数(四个参数),使其与给定的数据集(产生两个约束)保持一致,同时最小化函数的斜率和目标值(目标函数)之间的差异.因此,优化问题的结果是决定有理函数形状的四个参数.我正在用R Optimization Infrastructure (ROI)解这个模型.由于我想要为几种不同的情况求解模型,所以我创建了一系列接受变量的函数,以便可以轻松地更新目标函数和约束.

我的模特:

library(ROI)

# I installed several non-linear solvers that were suggested after running ROI_applicable_solvers() on the model
#install.packages("ROI.plugin.alabama")
#install.packages("ROI.plugin.nlminb")
#install.packages("ROI.plugin.nloptr")

# Empirical data for the example
elas_sl_t <- -0.006648
elas_by_t <- 0.2831
gdp_cap_rel_t <- 51.69
cal_cap_t <- 27.75

# Rational function for which parameters x[] need to be solved
elas_f <- function(x, gdp_cap) {
  (x[1]*gdp_cap + x[2])/((gdp_cap+x[3])*(gdp_cap+x[4]))
}

# Integral of elas_f
int_elas_f <- function(x, gdp_cap) {
  -(x[1] * x[4] - x[2]) * log(gdp_cap + x[4])/(x[4]^2 - x[3] * x[4]) - 
    (x[2] - x[1] * x[3]) * log(gdp_cap + x[3])/(x[3] * x[4] - x[3]^2) + x[2] * log(gdp_cap)/(x[3] * x[4])
}

# Derivative of elas_f
der_elas_f <- function(x, gdp_cap){
  - (x[1] * gdp_cap + x[2]) / ((gdp_cap + x[3])^2 * (gdp_cap + x[4])) -
    (x[1] * gdp_cap + x[2]) / ((gdp_cap + x[3]) * (gdp_cap + x[4])^2) + x[1] / ((gdp_cap + x[3]) * (gdp_cap + x[4]))
}

# Objective function (should be minimized)
obj_f <- function(x, gdp_cap = 1, elas_sl_by = elas_sl_t){
  (der_elas_f(x, gdp_cap) - elas_sl_by)^2
}

# 1st constraint (should be equal to zero)
con1_f <- function(x, gdp_cap = 1, elas_by = elas_by_t){
  elas_f(x, gdp_cap) - elas_by
}

# 2nd constraint (should be equal to zero)
con2_f <- function(x, gdp_cap_ty = gdp_cap_rel_t, gdp_cap_by = 1, cal_ty = cal_cap_t) {
  int_elas_f(x, gdp_cap = gdp_cap_ty) - int_elas_f(x, gdp_cap = gdp_cap_by) - log(cal_ty)
}

# The solution of the model is
param_t <- c(1245.685,  30.987, 883.645,  4.097)

# check the solution
con1_f(param_t) # close to zero, ok
con2_f(param_t) # close to zero, ok
obj_f(param_t) # 0.05155

# Solving the model with ROI, using the actual solution as starting values does not work.
nlp <- OP(F_objective(F = obj_f, n = 4), 
          F_constraint(F = list(con1_f, con2_f), dir = rep("==", 2), rhs = c(0,0)),
          maximum = FALSE)
nlp
sol <- ROI_solve(nlp, start = param_t, solver = "auto")
sol
solution(sol)

这个模型似乎无法解决,或者我做错了什么.是否有可能使用R(使用ROI或其他包)来解决上述问题?也许可用的解算器还不够好?我使用了GAMS CONOPT解算器来解决我的问题,这对于ROI/R是不可用的.我还使用了GAMS IPOPT解算器来解决问题,该解算器可用于R(https://github.com/coin-or/Ipopt),但不幸的是不是作为ROI的插件(仅限IPOP,它是二次求解器).我还在ROI中try 了NEOS解算器,但这导致了一条错误消息,因为无法联系服务器.任何帮助都是非常感激的.

推荐答案

我不确定你从GAMS得到的"解决方案".另外,什么被认为是"接近零"?

# Modified Integral of elas_f
int_elas_f <- function(x, gdp_cap) {
  if (any(gdp_cap + c(0, x[3:4]) < 0)) return(NA_real_)
  -(x[1] * x[4] - x[2]) * log(gdp_cap + x[4])/(x[4]^2 - x[3] * x[4]) - 
    (x[2] - x[1] * x[3]) * log(gdp_cap + x[3])/(x[3] * x[4] - x[3]^2) + x[2] * log(gdp_cap)/(x[3] * x[4])
}

with(
  optim(
    c(1e3, 100, 1e3, 10),
    function(x) {
      y <- obj_f(x)
      y + 1e3*(abs(y) + 1)*(abs(con1_f(x)) + abs(con2_f(x)))
    }
  ), list(par = par, constraints = c(con1_f(par), con2_f(par)), obj = obj_f(par), value = value)
)
#> $par
#> [1] 1361.293833  400.099856  880.053420    6.061782
#> 
#> $constraints
#> [1]  1.676616e-08 -2.059692e-08
#> 
#> $obj
#> [1] 0.0342367
#> 
#> $value
#> [1] 0.03427534

结果对最初的猜测相当敏感.一项更全面的探索表明,解决方案可能存在分歧:

library(data.table)

f <- function(x) {
    with(
      optim(
        x,
        function(x) {
          y <- obj_f(x)
          y + 1e3*(abs(y) + 1)*(abs(con1_f(x)) + abs(con2_f(x)))
        }, method = "Nelder-Mead"
      ),
      c(con1_f(par), con2_f(par), obj_f(par))
    )
  }

m <- Rcpp算法s::permuteGeneral(2^(8:20), 4)
n <- nrow(m)
df <- data.frame(con1 = numeric(n), con2 = numeric(n), obj = numeric(n))

for (i in 1:n) df[i,] <- f(m[i,])

dt <- setorder(setDT(df)[,r := .I][abs(con1) < 1e-6 & abs(con2) < 1e-6], obj)
m[dt$r[1],]
#> [1] 1048576    8192  131072    1024

sol <- with(
  optim(
    m[dt$r[1],],
    function(x) {
      y <- obj_f(x)
      y + 1e3*(abs(y) + 1)*(abs(con1_f(x)) + abs(con2_f(x)))
    }
  ),
  list(
    par = par,
    constraints = c(con1_f(par), con2_f(par)),
    obj = obj_f(par),
    value = value
  )
)

with(
  optim(
    sol$par,
    function(x) {
      y <- obj_f(x)
      y + 1e5*(abs(y) + 1)*(abs(con1_f(x)) + abs(con2_f(x)))
    }
  ),
  list(
    par = par,
    constraints = c(con1_f(par), con2_f(par)),
    obj = obj_f(par),
    value = value
  )
)
#> $par
#> [1]  4868827.420 24021111.619    30753.161     3317.202
#> 
#> $constraints
#> [1] -3.325118e-14  2.353673e-14
#> 
#> $obj
#> [1] 0.002944623
#> 
#> $value
#> [1] 0.002944629

随着我继续增加搜索空间中的初始值(例如,m <- Rcpp算法s::permuteGeneral(2^(12:24), 4)),参数值变得越来越大,而目标函数的值继续缩小.

不收敛的怀疑得到了ROI的支持,当它达到3.795066e-03的时候,它有停下来的感觉:

 library(ROI)
 
 param_t <- c(1245.685,  30.987, 883.645,  4.097)

 nlp <- OP(F_objective(F = obj_f, n = 4), 
           F_constraint(F = list(con1_f, con2_f), dir = rep("==", 2), rhs = c(0,0)),
           maximum = FALSE)
 sol <- ROI_solve(nlp, start = param_t, solver = "auto")
#> Warning in nlminb2(start = start, objective = objective(x), eqFun = eqfun, :
#> gradient not applicable for *constrained* NLPs for solver 'nlminb'.
 sol
#> No optimal solution found.
#> The solver message was: No solution.
#> The objective value is: 3.795066e-03
 sol$solution
#> [1] 3.262698e+06 1.350195e+07 1.333212e+02 4.250796e+05
 sol$status$msg$symbol
#> [1] "NON_CONVERGENCE"
 sol$message$message
#> [1] "false convergence (8)"

R相关问答推荐

如何将log 2刻度上的数字转换为自然log

变量计算按R中的行更改

如何在R中正确对齐放射状图中的文本

在垂直轴中包含多个ggplot2图中的平均值

为什么观察不会被无功值变化触发?

如何写一个R函数来旋转最后n分钟?

bslib::card_header中的shine::downloadButton,图标而不是文本

汇总数据表中两个特定列条目的值

对于变量的每个值,仅 Select 包含列表中所有值的值.R

将多列合并为单独的名称—值对

如何将Which()函数用于管道%>;%

将项粘贴到向量中,并将它们分组为x的倍数,用空格分隔

将全局环境变量的名称分配给列表中的所有元素

R中的类别比较

带RStatix的Wilcoxon环内检验

如何修改GT表中组名行的 colored颜色 ?

使用&Fill&Quot;在gglot中创建 colored颜色 渐变

在REST API中使用参数R

从矩阵创建系数图

是什么打破了此Quarto仪表板中的工具提示?