【问题标题】:R Error Genetic Programming ImplementationR错误遗传编程实现
【发布时间】:2016-06-11 20:04:10
【问题描述】:

所以我是 R 的新手。我昨天开始学习它,因为有些数据非常难以自动导入 Mathematica 和 Python。我正在构建一些机器学习技术来分析我现在可以使用 R 导入的数据。这是一个遗传编程实现,完成后应该对一些数据进行符号回归。 (我还没有创建突变或交叉运算符,建立一个合法的函数列表等)。运行脚本时出现两个错误:

> Error: attempt to apply non-function
> print(bestDude)
> Error in print(bestDude) : object 'bestDude' not found

这是我的代码:

library("datasets")

#Allows me to map a name to each element in a numerical list.
makeStrName<-function(listOfItems)
{
  for(i in 1:length(listOfItems))
  {
        names(listOfItems)[i]=paste("x",i,sep="")
  }
  return(listOfItems)
}

#Allows me to replace each random number in a vector with the corresponding 
#function in a list of functions.

mapFuncList<-function(funcList,rndNumVector)
{
  for(i in 1:length(funcList))
  {
    replace(rndNumVector, rndNumVector==i,funcList[[i]])
  }
  return(rndNumVector)
}

#Will generate a random function from the list of functions and a random sample.
generateOrganism<-function(inputLen,inputSeed, functions)
{
  set.seed(inputSeed)
  rnd<-sample(1:length(functions),inputLen,replace=T)
  Org<-mapFuncList(functions,rnd)
  return(Org)
}

#Will generate a series of "Organisms"
genPopulation<-function(popSize,initialSeed,initialSize,functions)
{
  population<-list("null")
  for(i in 2:popSize)
  {
    population <- c(population,generateOrganism(initialSize,initialSeed, functions))
    initialSeed <- initialSeed+1
  }
  populationWithNames<-makeStrName(population)
  return(populationWithNames)
}

#Turns the population of functions (which are actually strings in "") into
#actual functions. (i.e. changes the mode of the list from string to function).

populationFuncList<-function(Population)
{
  Population[[1]]<-"x"
  funCreator<-function(snippet)
    txt=snippet
  function(x)
  {
    exprs <- parse(text = txt)
    eval(exprs) 
  }
  listOfFunctions <- lapply(setNames(Population,names(Population)),function(x){funCreator(x)})
  return(listOfFunctions)
}

#Applies a fitness function to the population. Puts the best organism in
#the hallOfFame.
evalPopulation<-function(populationFuncList, inputData,outputData)
{   
  #rmse <- sqrt( mean( (sim - obs)^2))

  hallOfFame<-list(1000000000)
  for(i in 1:length(populationFuncList))
  {
        total<-list()
        for(z in 1:length(inputData))
        {
          total<-c(total,(abs(populationFuncList[[i]](inputData[[z]])-outputData[[z]])))
        }
        rmse<-sqrt(mean(total*total))
                   if(rmse<hallOfFame[[1]]) {hallOfFame[[1]]<-rmse}
  }
  return(hallOfFame)
}

#Function list, input data, output data (data to fit to)
funcs<-list("x","log(x)","sin(x)","cos(x)","tan(x)")
desiredFuncOutput<-list(1,2,3,4,5)
dataForInput<-list(1,2,3,4,5)

#Function calls
POpulation<-genPopulation(4,1,1,funcs)
POpulationFuncList<-populationFuncList(POpulation)
bestDude<-evalPopulation(POpulationFuncList,dataForInput,desiredFuncOutput)
print(bestDude)

感谢 Hack-R 的建议,代码现在可以运行了。所以这是最终的代码,以防其他人遇到类似的问题。

library("datasets")

#Allows me to map a name to each element in a numerical list.
makeStrName<-function(listOfItems)
{
  for(i in 1:length(listOfItems))
  {
    names(listOfItems)[i]=paste("x",i,sep="")
  }
  return(listOfItems)
}

#Allows me to replace each random number in a vector with the corresponding 
#function in a list of functions.

mapFuncList<-function(funcList,rndNumVector)
{
  for(i in 1:length(funcList))
  {
    rndNumVector[rndNumVector==i]<-funcList[i]
  }
  return(rndNumVector)
}

#Will generate a random function from the list of functions and a random sample.
generateOrganism<-function(inputLen,inputSeed, functions)
{
  set.seed(inputSeed)
  rnd<-sample(1:length(functions),inputLen,replace=T)
  Org<-mapFuncList(functions,rnd)
  return(Org)
}

#Will generate a series of "Organisms"
genPopulation<-function(popSize,initialSeed,initialSize,functions)
{
  population<-list()
  for(i in 1:popSize)
  {
    population <- c(population,generateOrganism(initialSize,initialSeed,functions))
    initialSeed <- initialSeed+1
  }
  populationWithNames<-makeStrName(population)
  return(populationWithNames)
}

#Turns the population of functions (which are actually strings in "") into
#actual functions. (i.e. changes the mode of the list from string to function).

funCreator<-function(snippet)
{
  txt=snippet
  function(x)
  {
    exprs <- parse(text = txt)
    eval(exprs) 
  }
}

#Applies a fitness function to the population. Puts the best organism in
#the hallOfFame.
evalPopulation<-function(populationFuncList, inputData,outputData)
{   
  #rmse <- sqrt( mean( (sim - obs)^2))

  hallOfFame<-list(1000000000)
  for(i in 1:length(populationFuncList))
  {
    total<-vector(mode="numeric",length=length(inputData))
    for(z in 1:length(inputData))
    {
      total<-c(total,(abs(populationFuncList[[i]](inputData[[z]])-outputData[[z]])))
    }
    rmse<-sqrt(mean(total*total))
    if(rmse<hallOfFame[[1]]) {hallOfFame[[1]]<-rmse}
  }
  return(hallOfFame)
}

#Function list, input data, output data (data to fit to)
funcs<-list("x","log(x)","sin(x)","cos(x)","tan(x)")
desiredFuncOutput<-list(1,2,3,4,5)
dataForInput<-list(1,2,3,4,5)

#Function calls
POpulation<-genPopulation(4,1,1,funcs)
POpulationFuncList <- lapply(setNames(POpulation,names(POpulation)),function(x){funCreator(x)})

bestDude<-evalPopulation(POpulationFuncList,dataForInput,desiredFuncOutput)
print(bestDude)

【问题讨论】:

    标签: r genetic-programming


    【解决方案1】:

    在您的函数evalPopulation 中,您尝试将populationFuncList[[i]] 应用为函数,但是当您传入参数POpulationFuncList 以替换变量populationFuncList 时,它不是函数,而是列表.

    我不确定你想做什么,所以我不确定你想用哪种方法来解决这个问题。如果您打算使用函数,则应该更改您引用该函数的对象的名称并将其作为参数删除,或者至少将函数作为参数而不是列表传递。

    OTOH,如果您打算使用列表 POpulationFuncList,那么您不应该将其应用为函数而不是列表。

    顺便说一句,如果你不给它们起类似的名字,这可能会更明显。

    另一个潜在问题是您的列表中似乎有非数字结果:

    > populationFuncList(POpulation)
    $x1
    [1] "x"
    
    $x2
    [1] 2
    
    $x3
    [1] 1
    
    $x4
    [1] 1
    

    你不能取字符“x”的绝对值,所以我只是想确保你知道这一点。

    第三个问题是您正在对名为total 的非数字数据类型对象进行数学运算。您需要将类型更改为数字或对其进行适当的索引。

    现在我不可能确切地知道你应该选择无数种可能性中的哪一种来解决这个问题,因为我不知道你的用例的细节。但是,这是一种可能的解决方案,您应该能够适应用例的具体情况:

    library("datasets")
    
    #Allows me to map a name to each element in a numerical list.
    makeStrName<-function(listOfItems)
    {
      for(i in 1:length(listOfItems))
      {
        names(listOfItems)[i]=paste("x",i,sep="")
      }
      return(listOfItems)
    }
    
    #Allows me to replace each random number in a vector with the corresponding 
    #function in a list of functions.
    
    mapFuncList<-function(funcList,rndNumVector)
    {
      for(i in 1:length(funcList))
      {
        replace(rndNumVector, rndNumVector==i,funcList[[i]])
      }
      return(rndNumVector)
    }
    
    #Will generate a random function from the list of functions and a random sample.
    generateOrganism<-function(inputLen,inputSeed, functions)
    {
      set.seed(inputSeed)
      rnd<-sample(1:length(functions),inputLen,replace=T)
      Org<-mapFuncList(functions,rnd)
      return(Org)
    }
    
    #Will generate a series of "Organisms"
    genPopulation<-function(popSize,initialSeed,initialSize,functions)
    {
      population<-list("null")
      for(i in 2:popSize)
      {
        population <- c(population,generateOrganism(initialSize,initialSeed, functions))
        initialSeed <- initialSeed+1
      }
      populationWithNames<-makeStrName(population)
      return(populationWithNames)
    }
    
    #Turns the population of functions (which are actually strings in "") into
    #actual functions. (i.e. changes the mode of the list from string to function).
    
    populationFuncList<-function(Population)
    {
      Population[[1]]<-"x"
      funCreator<-function(snippet)
        txt=snippet
      function(x)
      {
        exprs <- parse(text = txt)
        eval(exprs) 
      }
      listOfFunctions <- lapply(setNames(Population,names(Population)),function(x){funCreator(x)})
      return(listOfFunctions)
    }
    
    #Applies a fitness function to the population. Puts the best organism in
    #the hallOfFame.
    evalPopulation<-function(myList=myList, dataForInput,desiredFuncOutput)
    {   
      #rmse <- sqrt( mean( (sim - obs)^2))
    
      hallOfFame<-list(1000000000)
      for(i in 1:length(populationFuncList))
      {
        total<-0
        for(z in 1:length(dataForInput))
        {
          total<-c(total,(abs(myList[[i]]+(dataForInput[[z]])-desiredFuncOutput[[z]])))
        }
        rmse<-sqrt(mean(total*total))
        if(rmse<hallOfFame[[1]]) {hallOfFame[[1]]<-rmse}
      }
      return(hallOfFame)
    }
    
    #Function list, input data, output data (data to fit to)
    funcs<-list("x","log(x)","sin(x)","cos(x)","tan(x)")
    desiredFuncOutput<-list(1,2,3,4,5)
    dataForInput<-list(1,2,3,4,5)
    
    #Function calls
    POpulation<-genPopulation(4,1,1,funcs)
    myList <-populationFuncList(POpulation)[2:4]
    bestDude<-evalPopulation(myList,dataForInput,desiredFuncOutput)
    print(bestDude)
    [[1]]
    [1] 1.825742
    

    【讨论】:

    • 您好,谢谢您的帮助。我使用函数列表的方式基于:stackoverflow.com/questions/12117223/… 我使用的示例在底部。我很确定我使用它的方式是正确的。我唯一能想到的是,如果返回函数列表然后以这种方式应用它失败,或者在 for 循环中使用迭代器按顺序访问不同的函数是行不通的。列表是否类似于 C++ 数组,因为它们必须具有恒定长度?
    • 这个错误听起来确实是我使用函数列表的问题。感谢您指出了这一点。我没想到。
    • 不客气。但是你的不是函数列表,它只是一个列表***。它包含 4 个元素——一个字符串 (x) 和三个数字 (2, 1, 1)。这就是为什么您在问题中遇到错误以及为什么当您不将列表用作函数时错误消失的原因。要回答您的其他问题列表不必是恒定的长度。 ***如果您的意思是您的示例与您正在运行的实际代码不同,因为您的实际代码有一个函数列表,那么您应该更新问题中的代码,以便我们可以看到出了什么问题。
    • 哦。我打赌这是我的地图功能的问题。列表中的数字应该已转换为字符串,例如数字 1 的“x”、数字 2 的“log(x)”等。这会破坏整个程序。我没有意识到列表仍然是数字。我会尽力解决这个问题并回复你。
    • 酷,这可能就是答案。当您修复它(以及我发现的其他 1 或 2 件事,例如使用 total)时,代码应该可以正常工作。 :)
    猜你喜欢
    • 2010-10-31
    • 1970-01-01
    • 2015-03-08
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2015-10-24
    • 2011-09-13
    相关资源
    最近更新 更多