R中的二元遗传算法,具有强基数约束

机器算法验证 r 优化
2022-03-29 15:44:27

我试图在 R 中使用包 GA 来解决一个问题,我必须在 56 种仪器中找到 4 种的最佳组合。显然 56 种仪器中有 4 种组合的数量达到数十万,因此暴力方法是不可能的,特别是目标函数本身包含另一个优化并且速度很慢。所以遗传算法似乎很合适。然而 ga 函数,即使使用“type = binary”,似乎也无法具有基数约束。相反,文档(第 21 页)建议使用 AIC 或 BIC 信息标准,方法是在目标函数中加上一个惩罚,但我已经知道我只想要 4。这是我当前的代码:

gaopter <- function(xx) {
    a4 <- ay[, xx == 1]
    a4r <- ayr[, xx == 1]

    opter <- function(x) {
    # optimize for sd over vol, where a4 is a subcolumn of ay
        rets <- a4r %*% x
        outs <- a4 %*% x
        sdouts <- sd(outs)
        tomake <- (abs(last(outs) - mean(outs)) / sdouts - 1) * sdouts
        -(tomake / sd(rets))
        #(last(outs) - mean(outs)) / sd(outs)
    }
    optim(rep(1, ncol(a4)), opter)$value
}

ga(type = "binary", fitness = gaopter, nBits = ncol(ay), maxiter = 1000, run = 20000)

变量 ay 和 ayr 分别是 56 个向量及其每日回报的矩阵,所以我在上面尝试优化的是:56 个向量中的 4 个的最佳线性组合,使得它们的每日回报标准差最小化,而同时,该系列的最后一点尽可能远离均值。上面的代码只会找到满足上述条件的 56 个向量的最佳组合,没有任何基数约束。

像 4 这样的低基数约束的主要问题是,对于长度为 56 的 0 和 1 的随机二进制向量,它几乎永远不会只给我 4 个 1,其余的 0 是随机组合,所以放入某种基数 == 4 的惩罚将意味着什么都不会运行。我可以做些什么来将组合的基数限制为 4,使用包 GA 或其他?

1个回答

我将尝试使用交叉熵算法来解决它。这是 Reuven Rubenstein CE Method提出的一种方法。

基本上,这个想法是保持良好的解决方案并根据它们推断出参数。所以一般假设你想找到4个最低的SD。算法如下: 1. 为每个工具创建一个概率向量。2. 模拟多种解决方案。3.采取最好的ξ解决方案。4. 更新概率向量。

小型模拟。

> ## Creating Data
> 
> sig.vec      <- rep(1, 200) 
> low.sig.ind  <- sample(200, 4)
> sig.vec[low.sig.ind] <- 0.4 
> 
> ret <- t(replicate(300, rnorm(200, rep(0, 200), sig.vec)))
> 
> 
> 
> low.sig.ind
[1] 197 152  49  51
> ### Prepare running CE 
> iter     <- 100
> prob.vec <- runif(200) 
> sol.mat  <- matrix(NA, nrow = iter, ncol = 5)
> prob.list <- list()
> for (i in 1:10) {
+   ## Creating Sol 
+   for (j in 1:iter) {
+     temp.choice    <- sample(4, x = 200, prob = prob.vec)
+     sol.mat[j, ]   <- c(temp.choice, sd(apply(ret[,temp.choice], 1, sum)))
+   }
+   temp.tab <- table(factor(sol.mat[sol.mat[,5] <= quantile(sol.mat[,5], 0.1), 1:4], 
+                            levels = 1:200)) 
+   prob.vec <- temp.tab / sum(temp.tab)
+   prob.list[[i]] <- prob.vec
+ }
> 
> prob.vec[prob.vec == 0.25]

  10   49   72  152 
0.25 0.25 0.25 0.25 

所以它找到了正确的,当然这是一个玩具示例。