遗传算法 (GA) 选择向量的最佳 n 值

问题描述

我必须选择向量的 10 个元素来最大化函数。由于向量很长,因此有很多可能性(~1000 选择 10)来计算它们。所以我开始研究 GA 包以使用遗传算法。

我想出了这个 MWE:

values <- 1:1000


# fitness function which I want to maximise
f <- function(x){
  # Choose values
  y <- values[x]
  
  # From the first 10 sum up the odd values. 
  y <- ifelse(y %% 2 != 0,y,0) 
  y <- y[1:10]
  return(sum(y))
}

# Maximum value of f for this example
y <- ifelse(values %% 2 != 0,values,0) 
sum(sort(y,decreasing = TRUE)[1:10])
# [1] 9900 

# genetic algorithm
GA <- ga(type = "permutation",fitness = f,lower = rep(1,10),upper = rep(1000,maxiter = 100)
summary(GA)

结果有点令人失望。从 summary(GA) 开始,我觉得算法总是置换所有 1000 个值(解决方案从 x1 到 x1000),这导致优化效率低下。我如何告诉算法它应该只使用 10 个值(所以解决方案是 x1 .. x10)?

解决方法

您应该阅读https://www.jstatsoft.org/article/view/v053i04。您没有排列问题,但选择一个,因此您应该使用二进制类型的遗传算法。因为您只想选择 10 个(10 个 1 和 990 个零),所以您可能应该编写自己的遗传运算符,因为默认运算符几乎不会满足这种约束(如果您有,则在适应度函数中包含 -Inf超过 10 个零)。一种方法:

人口k 表示您想要多少):

myInit <- function(k){
  
  function(GA){
    m <- matrix(0,ncol = GA@nBits,nrow = GA@popSize)
    
    for(i in seq_len(GA@popSize))
      m[i,sample(GA@nBits,k)] <- 1 
  
    m
  }
}

交叉

myCrossover <- function(GA,parents){
  
  parents <- GA@population[parents,] %>%
    apply(1,function(x) which(x == 1)) %>%
    t()

  parents_diff <- list("vector",2)
  parents_diff[[1]] <- setdiff(parents[2,],parents[1,])
  parents_diff[[2]] <- setdiff(parents[1,parents[2,])
  
  children_ind <- list("vector",2)
  for(i in 1:2){
    k <- length(parents_diff[[i]])
    change_k <- sample(k,sample(ceiling(k/2),1))
    children_ind[[i]] <- if(length(change_k) > 0){
      c(parents[i,-change_k],parents_diff[[i]][change_k])
    } else {
      parents[i,]
    }
  }
  
  children <- matrix(0,nrow = 2,ncol = GA@nBits)
  for(i in 1:2)
    children[i,children_ind[[i]]] <- 1
  
  list(children = children,fitness = c(NA,NA))
}

突变

myMutation <- function(GA,parent){
  
  ind <- which(GA@population[parent,] == 1) 
  n_change <- sample(3,1)
  ind[sample(length(ind),n_change)] <- sample(setdiff(seq_len(GA@nBits),ind),n_change)
  parent <- integer(GA@nBits)
  parent[ind] <- 1
  
  parent
}

适应度(您的函数适用于二进制 GA):

f <- function(x,values){
  
  ind <- which(x == 1)
  y <- values[ind]
  y <- ifelse(y %% 2 != 0,y,0) 
  y <- y[1:10]
  return(sum(y))
}

GA

GA <- ga(
  type = "binary",fitness = f,values = values,nBits = length(values),population = myInit(10),crossover = myCrossover,mutation = myMutation,run = 300,pmutation = 0.3,maxiter = 10000,popSize = 100
)

选择的值

values[which(GA@solution[1,] == 1)]