如何优化 R 中的整数参数(和其他不连续参数空间)?

Posted

技术标签:

【中文标题】如何优化 R 中的整数参数(和其他不连续参数空间)?【英文标题】:How to optimize for integer parameters (and other discontinuous parameter space) in R? 【发布时间】:2012-06-22 01:48:53 【问题描述】:

如果参数空间只有整数(或不连续),如何优化?

在 optim() 中使用整数检查似乎不起作用,而且效率非常低。

fr <- function(x)    ## Rosenbrock Banana function
  x1 <- x[1]
  x2 <- x[2]
  value<-100 * (x2 - x1 * x1)^2 + (1 - x1)^2

  check.integer <- function(N)
    !length(grep("[^[:digit:]]", as.character(N)))
  

  if(!all(check.integer(abs(x1)), check.integer(abs(x2))))
   value<-NA 
  
  return(value)


optim(c(-2,1), fr)

【问题讨论】:

r.789695.n4.nabble.com/… 【参考方案1】:

这里有一些想法。

1.惩罚优化。 您可以四舍五入目标函数的参数 并对非整数加罚分。 但这会产生很多局部极值, 所以你可能更喜欢更健壮的优化程序, 例如,差分进化或粒子群优化。

fr <- function(x) 
  x1 <- round( x[1] )
  x2 <- round( x[2] )
  value <- 100 * (x2 - x1 * x1)^2 + (1 - x1)^2
  penalty <- (x1 - x[1])^2 + (x2 - x[2])^2
  value + 1e3 * penalty


# Plot the function
x <- seq(-3,3,length=200)
z <- outer(x,x, Vectorize( function(u,v) fr(c(u,v)) ))
persp(x,x,z,
  theta = 30, phi = 30, expand = 0.5, col = "lightblue", border=NA,
  ltheta = 120, shade = 0.75, ticktype = "detailed")

library(RColorBrewer)
image(x,x,z, 
  las=1, useRaster=TRUE,
  col=brewer.pal(11,"RdYlBu"),
  xlab="x", ylab="y"
)

# Minimize
library(DEoptim)
library(NMOF)
library(pso)
DEoptim(fr, c(-3,-3), c(3,3))$optim$bestmem
psoptim(c(-2,1), fr, lower=c(-3,-3), upper=c(3,3))
DEopt(fr, list(min=c(-3,-3), max=c(3,3)))$xbest
PSopt(fr, list(min=c(-3,-3), max=c(3,3)))$xbest

2。详尽的搜索。 如果搜索空间较小,也可以使用网格搜索。

library(NMOF)
gridSearch(fr, list(seq(-3,3), seq(-3,3)))$minlevels

3.本地搜索,包含用户指定的社区。​​strong> 在不调整目标函数的情况下,您可以使用某种形式的本地搜索, 您可以在其中指定要检查的点。 这应该快得多,但对邻域函数的选择极为敏感。

# Unmodified function
f <- function(x) 
  100 * (x[2] - x[1] * x[1])^2 + (1 - x[1])^2

# Neighbour function
# Beware: in this example, with a smaller neighbourhood, it does not converge.
neighbour <- function(x,...)
  x + sample(seq(-3,3), length(x), replace=TRUE)

# Local search (will get stuck in local extrema)
library(NMOF)
LSopt(f, list(x0=c(-2,1), neighbour=neighbour))$xbest
# Threshold Accepting
TAopt(f, list(x0=c(-2,1), neighbour=neighbour))$xbest

4.禁忌搜索。 为避免一次又一次地探索相同的点,您可以使用 tabu search, 即,记住最后的 k 点以避免再次访问它们。

get_neighbour_function <- function(memory_size = 100, df=4, scale=1)
  # Static variables
  already_visited <- NULL
  i <- 1
  # Define the neighbourhood
  values <- seq(-10,10)
  probabilities <- dt(values/scale, df=df)
  probabilities <- probabilities / sum(probabilities)
  # The function itself
  function(x,...) 
    if( is.null(already_visited) ) 
      already_visited <<- matrix( x, nr=length(x), nc=memory_size )
    
    # Do not reuse the function for problems of a different size
    stopifnot( nrow(already_visited) == length(x) )
    candidate <- x
    for(k in seq_len(memory_size)) 
      candidate <- x + sample( values, p=probabilities, length(x), replace=TRUE )
      if( ! any(apply(already_visited == candidate, 2, all)) )
        break
    
    if( k == memory_size ) 
      cat("Are you sure the neighbourhood is large enough?\n")
     
    if( k > 1 ) 
      cat("Rejected", k - 1, "candidates\n")
    
    if( k != memory_size ) 
      already_visited[,i] <<- candidate
      i <<- (i %% memory_size) + 1
    
    candidate
  

在下面的例子中,它并没有真正起作用: 我们只移动到最近的局部最小值。 而在更高维度,情况会变得更糟: 邻域如此之大,以至于我们从未访问过缓存 已经访问过的点。

f <- function(x) 
  result <- prod( 2 + ((x-10)/1000)^2 - cos( (x-10) / 2 ) )  
  cat(result, " (", paste(x,collapse=","), ")\n", sep="")
  result

plot( seq(0,1e3), Vectorize(f)( seq(0,1e3) ) )

LSopt(f, list(x0=c(0,0), neighbour=get_neighbour_function()))$xbest
TAopt(f, list(x0=c(0,0), neighbour=get_neighbour_function()))$xbest
optim(c(0,0), f, gr=get_neighbour_function(), method="SANN")$par

差分进化效果更好:我们只得到一个局部最小值, 但它比最近的要好。

g <- function(x) 
  f(x) + 1000 * sum( (x-round(x))^2 )
DEoptim(g, c(0,0), c(1000,1000))$optim$bestmem

禁忌搜索通常用于纯粹的组合问题 (例如,当搜索空间是一组树或图时) 并且对于整数问题似乎不是一个好主意。

【讨论】:

教科书质量的答案!美丽的情节说明了问题!非常感谢!我虽然会有不连续和/或整数函数的特定方法。您可能是回答这个附带问题的最佳人选:有没有一种方法可以优化给定每个参数的向量参数空间(例如 1:1000),而无需简单地探索整个参数空间?这可能比搜索惩罚的连续有界空间更有效,即使我们必须搜索整个空间(与可比较的连续空间相比,这仍然是一个小空间)。 如果搜索空间不太大,可以使用穷举搜索(网格搜索)。否则,您可以通过选择邻域函数并使用一些局部算法来搜索大的离散空间:局部搜索、阈值接受、模拟退火(@HansWerner 的回答)。阈值接受类似于模拟退火,但更具确定性:它收敛得更快,但频率更低,并且对邻域的选择更敏感。您应该使用实际函数进行测试:模拟退火通常要慢得多,但对整数的限制应该会加快速度。 LSopt 和 TAopt 都不记得他们去过哪里的事实意味着他们倾向于在我的函数中转圈。 Tabu search 是那些记住哪些点已经被探索过的算法的变体。有一个tabuSearch 包,但不幸的是它仅限于二进制搜索空间。但是,您可以修改LSoptTAopt 的邻域函数,使其记住最后k 个点并避开它们。 我已经用更多关于禁忌搜索的细节编辑了我的答案,但它似乎不适用于整数问题。【参考方案2】:

整数规划 (IP) 有自己的规则和算法。使用连续求解器没有多大意义。 R 没有专门的整数规划求解器,但您可以尝试:

如果您的函数是线性的,请使用混合整数规划之一 求解器,例如 lp_solve 在 R 中作为“lpSolve”或 GLPK 在 R 中作为“Rglpk”。

否则,您可以尝试使用“SANN”方法进行优化,这是一种模拟退火 方法,文档说:

"It uses only function values but is relatively slow... If a function to generate a new candidate point is given, method 'SANN' can also be used to solve combinatorial optimization problems... Note that the 'SANN' method depends critically on the settings of the control parameters."

下面是[-10,10]x[-10,10] 中的翻译球体函数示例:

fun <- function(x) sum((x-c(3.2, 6.7))^2)
nextfun <- function(x) sample(-10:10, 2, replace=TRUE)

optim(fn=fun, par=c(-10,-10), gr=nextfun, method="SANN", 
      control=list(maxit=1000,fnscale=1,trace=10))

# sann objective function values
# initial       value 458.000000
# iter      999 value 0.000000
# final         value 0.000000
# sann stopped after 999 iterations
# $par
# [1] 3 7
# $value
# [1] 0.13

但是您应该应用比随机采样更智能的“梯度”,或者在没有其他帮助的情况下全面搜索您的整数域。当然,在更高维度上,需要一种专门的方法。

【讨论】:

我希望我能接受两个答案,因为它们都是互补的,并且可以一起形成一个完美的完整答案!非常感谢!【参考方案3】:

R 中有一些新的包允许在优化程序中使用不连续的输入参数(例如整数)。其中之一是rgenoud

使用选项“data.type.int=TRUE”并通过设置正确的边界,函数将仅使用整数来最小化或最大化给定函数。

rgenoud 下面使用 stats::optim() 进行优化。因此,用户可以将任何选项传递给 rgenoud,它通常会传递给 optim()

【讨论】:

以上是关于如何优化 R 中的整数参数(和其他不连续参数空间)?的主要内容,如果未能解决你的问题,请参考以下文章

求助,VB函数的参数个数未知,要如何传递参数

解释问题的价值与R中的优化函数相同

如何使用带有R的遗传算法优化支持向量机的参数

杂题之求1-100连续不重复整数中的缺少的一个数

[冬令营Day1 T2]sequence

运行java jar时整数数组作为参数