Реализация генетического программирования ошибок R

Итак, я новичок в 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)

person Novice Polymath    schedule 11.06.2016    source источник


Ответы (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
person Hack-R    schedule 11.06.2016
comment
Привет, спасибо за помощь. То, как я использую свой список функций, основано на: stackoverflow.com/questions/12117223/ Пример, который я использую, находится внизу. Я почти уверен, что я использую его правильно. Единственное, о чем я могу думать, - это если вернуть список функций, а затем применить его таким образом, или что использование итератора в цикле for для последовательного доступа к различным функциям не работает. Являются ли списки подобными массивам C ++ в том смысле, что они должны быть постоянной длины? - person Novice Polymath; 12.06.2016
comment
Ошибка звучит так, будто это проблема с тем, как я использую свой список функций. Спасибо что подметил это. Я не думал об этом. - person Novice Polymath; 12.06.2016
comment
Пожалуйста. Но у вас не список функций, это просто список ***. Он содержит 4 элемента - одну строку (x) и три числовых (2, 1, 1). Вот почему вы получили ошибку в своем вопросе и почему ошибка исчезает, если вы не используете список как функцию. Чтобы ответить на другие ваши вопросы, списки не должны быть постоянной длины. *** Если вы имеете в виду, что ваш пример отличается от реального кода, который вы выполняете, в котором ваш фактический код имеет список функций, то вам следует обновить код в своем вопросе как таковой, чтобы мы могли увидеть, что пошло не так. - person Hack-R; 12.06.2016
comment
Оххх. Бьюсь об заклад, это проблема с моей функцией карты. Числа в списке должны быть преобразованы в строки, такие как x для числа 1, log (x) для числа 2 и т. Д. Это сломало бы всю программу. Я не понимал, что список все еще числовой. Я постараюсь исправить это и вернусь к вам. - person Novice Polymath; 12.06.2016
comment
Круто, наверное, это и есть ответ. Когда вы исправите это (и 1 или 2 другие вещи, которые я уловил, например, использование total), тогда код должен сработать. :) - person Hack-R; 12.06.2016
comment
Код теперь работает. Большое спасибо за помощь! - person Novice Polymath; 12.06.2016
comment
@NovicePolymath Рад это слышать! - person Hack-R; 12.06.2016