R Error Genetic Programming Implementation - r
So I am brand new to R. I started learning it yesterday, because there's some data that is being very resistant to automatically importing into Mathematica and Python. I'm building a few machine learning techniques to do analysis on the data that I can now import with R. This is a genetic programming implementation that when finished should do symbolic regression on some data. (I have yet to create the mutation or crossover operators, build a legit function list, etc). I get two errors when I run the script:
> Error: attempt to apply non-function
> print(bestDude)
> Error in print(bestDude) : object 'bestDude' not found
This is my code:
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)
The code is now working thanks to Hack-R's suggestions. So here's the finalized code in case someone else runs into a similar trouble.
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)
In your function evalPopulation you're attempting to apply populationFuncList[[i]] as if it were a function, but when you pass in the argument POpulationFuncList to replace the variable populationFuncList it's not a function, it's a list.
I'm not sure what you were trying to do, so I'm not sure which way you want to fix this. If you meant to use a function you should change the name of the object you're referencing to the function and remove it as an argument or at least pass a function in as an argument instead of the list.
OTOH if you meant to use the list POpulationFuncList then you just shouldn't be applying it as if it were a function instead of a list.
On a side note, this probably would be more apparent if you didn't give them such similar names.
Another potential problem is that you seem have non-numeric results in one of your lists:
> populationFuncList(POpulation)
$x1
[1] "x"
$x2
[1] 2
$x3
[1] 1
$x4
[1] 1
You can't take the absolute value of the character "x", so I just wanted to make sure you're aware of this.
A third problem is that you're doing math on a non-numeric data typed object called total. You need to either change the type to numeric or index it appropriately.
Now it's impossible for me to know exactly which of an infinite number of possibilities you should choose to fix this, because I don't know the details of your use case. However, here is one possible solution which you should be able to adapt to the specifics of the use case:
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
Related
Using SVD on each matrix in a list
I'm trying to use the svd() function on all matrices within a list. Currently, the results only appear for the first matrix in the list. How can this be done for every matrix in the list? svd_list <- function(data) { for (i in 1:length(data)) { svd <- svd(data[[i]]) return(svd$d) } }
You are over writing the results in svd in each iteration. Initialise an empty list to store the results. svd_list <- function(data) { svd <- vector('list', length(data)) for (i in 1:length(data)) { svd[[i]] <- svd(data[[i]])$d } return(svd) } Alternatively, you can use lapply : svd_list <- function(data) { lapply(data, function(x) svd(x)$d) }
R GP Implementation Error
So I am very new to R. I was having some trouble importing data with Mathematica, so I decided to make a switch since R is much better suited to analytics. I'm building a few machine learning techniques to do analysis on the data that I can now import. This is a genetic programming implementation that when finished should do symbolic regression on some data. Other than the errors, the script should be almost complete (I need to program the composition operator, make the division protected, and finish the list of base functions). I had a previous problem while programming the script that was resolved (R Error Genetic Programming Implementation). I've been debugging the script for about a day and I'm all out of ideas. My error message is: Error in makeStrName(nextGen) : object 'nextGen' not found > > #Print the string versions of the five functions with the lowest RMSE evolved. > byRMSEList<-sortByRMSE(populationsBestTenStr) Error: object 'totalTwo' not found > for(i in 1:5) + { + byRMSEList[[i]] + } Error: object 'byRMSEList' not found Here is my script. I am currently using RStudio. Thanks for taking the time to help: library("datasets") operators<-list("+","*","-","/","o") funcs<-list("x","log(x)","sin(x)","cos(x)","tan(x)") #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, funcList) { set.seed(inputSeed) rnd<-sample(1:length(funcList),inputLen,replace=T) Org<-mapFuncList(funcList,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+i,functions)) } 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, populationStringList) { #rmse <- sqrt( mean( (sim - obs)^2)) for(i in 1:length(populationStringList)) { stringFunc<-populationStringList[[i]] total<-list(mode="numeric",length=length(inputData)) topTenPercentFunctionList<-list() topTenPercentRMSEList<-list() topTenPercentStringFunctionList<-list() tempFunc<-function(x){x} for(z in 1:length(inputData)) { total<-c(total,(abs(populationFuncList[[i]](inputData[[z]])-outputData[[z]]))) tempFunc<-populationFuncList[[i]] } rmse<-sqrt(mean(total*total)) topTenPercentVal<-length(populationFuncList)*0.1 if(length(topTenPercentFunctionList)<topTenPercentVal||RMSE<min(topTenPercentRMSEList)) { topTenPercentStringFunctionList<-c(topTenPercentStringFunctionList,stringFunc) topTenPercentRMSEList<-c(topTenPercentRMSEList, rmse) topTenPercentFunctionList<-c(topTenPercentFunctionList, tempFunc) } } return(topTenPercentStringFunctionList) } #Get random operator getRndOp<-function(seed) { set.seed(seed) rndOpNum<-sample(1:length(operators),1,replace=T) operation<-operators[[rndOpNum]] return(operation) } #Mutation Operators #This attaches a new appendage to an organism endNodeMutation<-function(strFunc,seed) { op<-getRndOp(seed) strFunc<-c(strFunc,op) newAppendage<-generateOrganism(1,seed+2,funcs) strFunc<-c(strFunc,newAppendage) return(strFunc) } #This is a mutation that occurs at a random locaiton in an organism rndNodeMutation<-function(strFunc,seed,secondSeed) { op<-getRndOp(seed) halfStrFunc<-((length(strFunc))/2) set.seed(seed) randomStart<-sample(1:halfStrFunc,1,replace=T) set.seed(secondSeed) randomEnd<-2*(sample(1:length(halfStrFunc),1,replace=T)) strFuncUpdate<-substr(strFunc,randomStart,randomEnd) strFuncUpdate<-c(strFuncUpdate,op) newAppendage<-generateOrganism(1,seed+2,funcs) strFuncUpdate<-c(strFuncUpdate,newAppendage) return(strFuncUpdate) } #Crossover Operators #Crossover operator that attaches otherStrFunc to strFunc at the endpoint of strFunc crossoverConcatenationOperator<-function(strFunc,otherStrFunc) { newStrFunc<-c(strFunc,otherStrFunc) return(newStrFunc) } #Crossover Operation that starts and ends at random points in the concatenation randomCrossoverOperator<-function(strFunc,otherStrFunc,seed,secondSeed) { set.seed(seed) wholeLength<-(length(strFunc)+length(otherStrFunc)) startRndNum<-sample(1:length(strFunc),1,replace=T) set.seed(secondSeed) endRndNum<-sample(length(strFunc):wholeLength,1,replace=T) concatenatedFunc<-c(strFunc,otherStrFunc) newFunc<-substr(concatenatedFunc,startRndNum,endRndNum) return(newFunc) } evolve<-function(strFuncList,tenPercentStrFuncList) { #Detach the bottom ninety percent to the top ten percent evolveList<-substr(strFuncList,length(tenPercentStrFuncList),length(strFuncList)) #Get sizes. Will use a random mutation, then random crossover, then #random mutation, then random crossover at percentages with 0.05,0.45,0.05,0.45 #respectively size<-length(evolveList) mutateNum<-0.1*size crossoverNum<-0.9*size halfMutateNum<-0.05*size halfCrossoverNum<-0.45*size roundedMutateNum<-floor(mutateNum) roundedCrossoverNum<-floor(crossoverNum) roundedHalfMutateNum<-floor(halfMutateNum) roundedHalfCrossoverNum<-floor(halfCrossoverNum) #Calls the functions for those percentage of organisms in that order for(i in 1:roundedHalfMutateNum) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndNodeMutation(evolveList[[i]],rndOne,rndTWo) evolveList[[i]]<-newFunc } for (i in roundedHalfMutateNum:(roundedHalfCrossoverNum+roundedHalfMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndCrossoverOperation(evolveList[[i]],evolveList[[i+1]],rndOne,rndTwo) firstSubstr<-substr(evolveList,1,i-1) secondSubstr<-substr(evolveLIst,i+2,length(evolveList)) halfSubstr<-c(firstSubstr,newFunc) evolveList<-c(halfSubstr,secondSubstr) } for(i in (roundedHalfCrossoverNum+roundedHalfMutateNum):(roundedHalfCrossoverNum+roundedMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndNodeMutation(evolveList[[i]],rndOne,rndTWo) evolveList[[i]]<-newFunc } for(i in (roundedHalfCrossoverNum+roundedMutateNum):(roundedCrossoverNum+roundedHalfMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndCrossoverOperation(evolveList[[i]],evolveList[[i+1]],rndOne,rndTwo) firstSubstr<-substr(evolveList,1,i-1) secondSubstr<-substr(evolveLIst,i+2,length(evolveList)) halfSubstr<-c(firstSubstr,newFunc) evolveList<-c(halfSubstr,secondSubstr) } } #Calculates the root mean squared of the functions in a string list. #Then sorts the list by RMSE. sortByRMSE<-function(strL) { for (z in 1:length(strL)) { for(i in 1:length(strL)) { nonStrFuncList<-lapply(strL,function(x){funCreator(x)}) totalTwo<-c(totalTwo,(abs(nonStrFuncList[[z]](inputData[[i]])-outputData[[i]]))) } rmse<-sqrt(mean(totalTwo*totalTwo)) strFuncsLists<-strL[order(sapply(strL, '[[', rmse))] } return(strFuncsLists) } #Data, Output Goal desiredFuncOutput<-list(1,4,9,16,25) dataForInput<-list(1,2,3,4,5) #Generate Initial Population POpulation<-genPopulation(4,1,1,funcs) POpulationFuncList <- lapply(setNames(POpulation,names(POpulation)),function(x){funCreator(x)}) #Get and save top ten percent in bestDudes bestDudes<-evalPopulation(POpulationFuncList,dataForInput,desiredFuncOutput,POpulation) #Evolve the rest NewBottomNinetyPercent<-evolve(POpulation,bestDudes) #Concatenate the two to make a new generation nextGen<-c(bestDudes,NewBottomNinetyPercent) #Declare lists, populationsBestTenStr<-list() populationsFuncList<-list() #Run ten generations. for(i in 1:10) { nextGen<-makeStrName(nextGen) populationsFuncList<-lapply(setNames(nextGen,names(nextGen)),function(x){funCreator(x)}) populationsBestTenStr<-evalPopulation(populationsFuncList,dataForInput,desiredFuncOutput,nextGen) nextGen<-evolve(populations,populationsBestTenStr) } #Print the string versions of the five functions with the lowest RMSE evolved. byRMSEList<-sortByRMSE(populationsBestTenStr) for(i in 1:5) { byRMSEList[[i]] }
library("datasets") operators<-list("+","*","-","/","o") funcs<-list("x","log(x)","sin(x)","cos(x)","tan(x)") # Fixed: # evolveLIst inconsistently typed as evolveList # rndCrossoverOperation inconsistently typed as randomCrossoverOperator # rndTWo inconsistently typed as rndTwo # broken substr # broken condition leading to for(i in 1:0) # misc. others #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, funcList) { set.seed(inputSeed) rnd<-sample(1:length(funcList),inputLen,replace=T) Org<-mapFuncList(funcList,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+i,functions)) } 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=POpulationFuncList, inputData=dataForInput, outputData=desiredFuncOutput, populationStringList=POpulation) { #rmse <- sqrt( mean( (sim - obs)^2)) for(i in 1:length(populationStringList)) { stringFunc<-populationStringList[[i]] total<-as.numeric(length(inputData)) topTenPercentFunctionList<-list() topTenPercentRMSEList<-list() topTenPercentStringFunctionList<-list() tempFunc<-function(x){x} for(z in 1:length(inputData)) { total<-c(total,(abs(populationFuncList[[i]](inputData[[z]])-outputData[[z]]))) tempFunc<-populationFuncList[[i]] } rmse<-sqrt(mean(total^2)) topTenPercentVal<-length(populationFuncList)*0.1 if(length(topTenPercentFunctionList)<topTenPercentVal||RMSE<min(topTenPercentRMSEList)) { topTenPercentStringFunctionList<-c(topTenPercentStringFunctionList,stringFunc) topTenPercentRMSEList<-c(topTenPercentRMSEList, rmse) topTenPercentFunctionList<-c(topTenPercentFunctionList, tempFunc) } } return(topTenPercentStringFunctionList) } #Get random operator getRndOp<-function(seed) { set.seed(seed) rndOpNum<-sample(1:length(operators),1,replace=T) operation<-operators[[rndOpNum]] return(operation) } #Mutation Operators #This attaches a new appendage to an organism endNodeMutation<-function(strFunc,seed) { op<-getRndOp(seed) strFunc<-c(strFunc,op) newAppendage<-generateOrganism(1,seed+2,funcs) strFunc<-c(strFunc,newAppendage) return(strFunc) } #This is a mutation that occurs at a random locaiton in an organism rndNodeMutation<-function(strFunc,seed,secondSeed) { op<-getRndOp(seed) halfStrFunc<-((length(strFunc))/2) set.seed(seed) randomStart<-sample(1:halfStrFunc,1,replace=T) set.seed(secondSeed) randomEnd<-2*(sample(1:length(halfStrFunc),1,replace=T)) strFuncUpdate<-substr(strFunc,randomStart,randomEnd) strFuncUpdate<-c(strFuncUpdate,op) newAppendage<-generateOrganism(1,seed+2,funcs) strFuncUpdate<-c(strFuncUpdate,newAppendage) return(strFuncUpdate) } #Crossover Operators #Crossover operator that attaches otherStrFunc to strFunc at the endpoint of strFunc crossoverConcatenationOperator<-function(strFunc,otherStrFunc) { newStrFunc<-c(strFunc,otherStrFunc) return(newStrFunc) } #Crossover Operation that starts and ends at random points in the concatenation rndCrossoverOperation<-function(strFunc,otherStrFunc,seed,secondSeed) # fixed function name { set.seed(seed) wholeLength<-(length(strFunc)+length(otherStrFunc)) startRndNum<-sample(1:length(strFunc),1,replace=T) set.seed(secondSeed) endRndNum<-sample(length(strFunc):wholeLength,1,replace=T) concatenatedFunc<-c(strFunc,otherStrFunc) newFunc<-substr(concatenatedFunc,startRndNum,endRndNum) return(newFunc) } evolve<-function(strFuncList=POpulation,tenPercentStrFuncList=bestDudes) { #Detach the bottom ninety percent to the top ten percent evolveList<-strFuncList[!strFuncList %in% tenPercentStrFuncList] # fixed broken substring #Get sizes. Will use a random mutation, then random crossover, then #random mutation, then random crossover at percentages with 0.05,0.45,0.05,0.45 #respectively size<-length(evolveList) mutateNum<-0.1*size crossoverNum<-0.9*size halfMutateNum<-0.05*size halfCrossoverNum<-0.45*size roundedMutateNum<-floor(mutateNum) roundedCrossoverNum<-floor(crossoverNum) roundedHalfMutateNum<-floor(halfMutateNum) roundedHalfCrossoverNum<-floor(halfCrossoverNum) #Calls the functions for those percentage of organisms in that order if(roundedHalfMutateNum < 1) roundedHalfMutateNum <- 1 for(i in 1:roundedHalfMutateNum) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndNodeMutation(evolveList[[i]],rndOne,rndTwo) # fixed case evolveList[[i]]<-newFunc } for (i in roundedHalfMutateNum:(roundedHalfCrossoverNum+roundedHalfMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndCrossoverOperation(evolveList[[i]],evolveList[[i+1]],rndOne,rndTwo) firstSubstr<-substr(evolveList,1,i-1) secondSubstr<-substr(evolveList,i+2,length(evolveList)) halfSubstr<-c(firstSubstr,newFunc) evolveList<-c(halfSubstr,secondSubstr) } for(i in (roundedHalfCrossoverNum+roundedHalfMutateNum):(roundedHalfCrossoverNum+roundedMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndNodeMutation(evolveList[[i]],rndOne,rndTwo) evolveList[[i]]<-newFunc } for(i in (roundedHalfCrossoverNum+roundedMutateNum):(roundedCrossoverNum+roundedHalfMutateNum)) { set.seed(i) rndOne<-sample(0:1000,1,replace=T) set.seed(i+10000) rndTwo<-sample(0:10000,1,replace=T) newFunc<-rndCrossoverOperation(evolveList[[i]],evolveList[[i+1]],rndOne,rndTwo) firstSubstr<-substr(evolveList,1,i-1) secondSubstr<-substr(evolveList,i+2,length(evolveList)) halfSubstr<-c(firstSubstr,newFunc) evolveList<-c(halfSubstr,secondSubstr) } } #Calculates the root mean squared of the functions in a string list. #Then sorts the list by RMSE. sortByRMSE<-function(strL) { for (z in 1:length(strL)) { for(i in 1:length(strL)) { nonStrFuncList<-lapply(strL,function(x){funCreator(x)}) totalTwo<-c(totalTwo,(abs(nonStrFuncList[[z]](inputData[[i]])-outputData[[i]]))) } rmse<-sqrt(mean(totalTwo*totalTwo)) strFuncsLists<-strL[order(sapply(strL, '[[', rmse))] } return(strFuncsLists) } #Data, Output Goal desiredFuncOutput<-list(1,4,9,16,25) dataForInput<-list(1,2,3,4,5) #Generate Initial Population POpulation<-genPopulation(4,1,1,funcs) POpulationFuncList <- lapply(setNames(POpulation,names(POpulation)),function(x){funCreator(x)}) #Get and save top ten percent in bestDudes bestDudes<-evalPopulation(POpulationFuncList,dataForInput,desiredFuncOutput,POpulation) #Evolve the rest NewBottomNinetyPercent<-evolve(POpulation,bestDudes) #Concatenate the two to make a new generation nextGen<-c(bestDudes,NewBottomNinetyPercent) #Declare lists, populationsBestTenStr<-list() populationsFuncList<-list() #Run ten generations. for(i in 1:10) { nextGen<-makeStrName(nextGen) populationsFuncList<-lapply(setNames(nextGen,names(nextGen)),function(x){funCreator(x)}) populationsBestTenStr<-evalPopulation(populationsFuncList,dataForInput,desiredFuncOutput,nextGen) nextGen<-evolve(populations,populationsBestTenStr) } #Print the string versions of the five functions with the lowest RMSE evolved. byRMSEList<-sortByRMSE(populationsBestTenStr) for(i in 1:5) { byRMSEList[[i]] }
How can I discriminate between functions in R
I have been trying to write a code capable of using different classification functions. However, the arguments are different depending on the classification function I use. I would like to have something like this : classification_flow <- function(classification_function, ...) { if (classification_function == randomForest) { ... } else if (classification_function == svm) { ... } } Of course, this doesn't work since == wasn't built for functions. I've tried using str, names, attr, and looked a bit at methodsand UseMethod, but I can't find a suitable way to do so. Can anybody help me? Thanks, Jess PS : In this particular case, what I'm trying to do is to get a matrix of probabilities as the output, so something like that : classification_flow <- function(classification_function, train, classes, ...) { if (classification_function == randomForest) { mat = classification_function(train, classes, type="prob") } else if (classification_function == svm) { mat = classification_function(train, classes, probabilities = T) } return(mat) } If you know a more elegant solution...
You are looking for substitute: f <- function(x, FUN) { if (substitute(FUN) == 'max') { print('Max invoked') } FUN(x) } > f(1:4, sum) [1] 10 > f(1:4, max) [1] "Max invoked" [1] 4
Here's a version that can get a character or a function. Then you can do character comparisons to find the right case. classification_flow <- function(classification_function, train, classes, ...) { if (is.function(classification_function)) { fname <- deparse(substitute(classification_function)) } else if (is.character(classification_function)) { fname <- classification_function classification_function < - get(classification_function) } else { stop("invalid classification_function") } if (fname == "randomForest") { mat = classification_function(train, classes, type="prob") } else if (fname == "svm") { mat = classification_function(train, classes, probabilities = T) } return(mat) }
First, make the input to classification_function a character input. Then, use the switch function to chose between your two options like so: classification_flow <- function(classification_function, train, classes, ...) { switch(classification_function, randomForrest= {mat<-classification_function(train, classes, type="prob")}, svm = { mat<-classification_function(train, classes, probabilities = T) }, stop("You did not pick randomForrest or svm") ) return(mat) } Edit: Added the stop line that gives an error message if neither choice is selected. After you designate all of the options (e.g. svm=) you can add a final line to be executed if there are no prior matches.
You may be able to use the formals function to determine which arguments the function is expecting, then call it accordingly. Also see do.call for a way to dynamically create a function call and call it.
Using self-defined functions in R to produce different random numbers Each time
I am trying to produce different uniform numbers using the Lehmar random number generator. I believe I have done this but I have a problem in producing different numbers each time I execute this function. Below is the code I am trying to do and I will explain the problem further underneath it. MODULUS <- 2147483647 MULTIPLIER <- 48271 put_Seed <- function(x) { x <- (if ( x > 0) { x%%MODULUS } else { 1000*as.numeric(Sys.time()) } ) } T_val <- function(Rand) { Q <- floor(MODULUS / MULTIPLIER) R <- MODULUS%%MULTIPLIER; floor(MULTIPLIER*(Rand%%Q) - R*(Rand/Q)) } New_Random_Seed <- function(T_value_i) { Random_Seed <- (if (T_value_i > 0) { T_value_i; } else { T_value_i + MODULUS }) } Random <- function(New_Seed) { New_Seed/MODULUS } uniform_num <- function(a, b, r) { a + (b - a) * r } Random_Seed <- put_Seed(123456789) uni_num <- function(k) { Random_Seed <- put_Seed(k) T_value <- T_val(Random_Seed) Random_Seed <- New_Random_Seed(T_value) uniform_num(0, 1, Random(Random_Seed)) } test1 <- uni_num(Random_Seed) test2 <- uni_num(Random_Seed) test3 <- uni_num(Random_Seed) #Results #test1 = 0.05380306 #test2 = 0.05380306 #test3 = 0.05380306 What I am trying to do is whenever I run the uni_num function that each time, the Random_Seed gets updated and the uniform_num(0, 1, Random(Random_Seed)) line produces a random uniform number between 0 and 1 each time the function is executed. The code works for 1 repetition but if I try to use the function again the Random_Seed has not being updated and hence the function will produce the same random number as before. This is undesirable as I wish to produce different random number's each time by having the Random_Seed updated after each repetition. Forgive me if there is a simple solution but my head is wrecked from trying to find an answer. Cheers :)
In this function: uni_num <- function(k) { Random_Seed <- put_Seed(k) T_value <- T_val(Random_Seed) Random_Seed <- New_Random_Seed(T_value) uniform_num(0, 1, Random(Random_Seed)) } The target of the assignment Random_Seed <- is in the environment of the function body, and not the global environment. Thus, when you make a second call, Random_Seed in the global environment has not been modified, and you get the same results. To write to the global environment instead, use <<-: Random_Seed <<- New_Random_Seed(T_value) It looks like this is the only assignment that must be modified, as New_Random_Seed returns a value and doesn't require modification of this global object. In addition, the first assignment to Random_Seed in uni_num might as well be in the function body environment. Note that it's bad form for a function to write to the global environment. There's always a better way. But this will work for your example code.
*apply in r to repeat a function
I've written a function that is a simulation, that outputs a vector of 100 elements, and I want to use the *apply functions to run the function many times and store the repeated output in a new vector for each time the simulation is run. The function looks like: J <- c(1:100) species_richness <- function(J){ a <- table(J) return(NROW(a)) } simulation <- function(J,gens,ploton=FALSE,v=0.1){ species_richness_output <- rep(NA,gens) for(rep in 1:gens){ index1 <- sample(1:length(J),1) if(runif(1,0,1) < v){ J[index1] <- (rep+100) } else{ index2 <- sample(1:length(J),1) while(index1==index2) { index2 <- sample(1:length(J),1) } J[index1] <- J[index2] } species_richness_output[rep] <- species_richness(J) } species_abundance <- function(J){ a <- table(J) return(a) } abuntable <- species_abundance(J) print(abuntable) octaves <- function(abuntable){ oct <- (rep(0,log2(sum(abuntable)))) for(i in 1:length(abuntable)){ oct2 <- floor(log2(abuntable[i])+1) oct[oct2] <- oct[oct2]+1 } print(oct) } # octaves(c(100,64,63,5,4,3,2,2,1,1,1,1)) if(ploton==TRUE){ hist(octaves(abuntable)) } print(species_richness(J)) return(J) } simulation(J, 10000,TRUE,v=0.1) So that's my function, it takes J a vector I defined earlier, manipulates it, then returns: the newly simulated vector J of 100 elements a function called octave that categorises the new vector a histogram corresponding to the above "octave" I have tried a number of variations: using lapply, mapply putting args=args_from_original_simulation simulation_repeated <- c(mapply(list, FUN=simulation(args),times=10000)) but I keep getting an error with the match.fun part of the mapply function Error in match.fun(FUN) : 'simulation(J, 10000, FALSE, 0.1)' is not a function, character or symbol This is despite the simulation I have written showing as being saved as a function in the workspace. Does anyone know what this error is pointing to?
In this line: simulation_repeated <- c(mapply(list, FUN=simulation(args),times=10000)) You are not giving a function to mapply. You are (essentially) passing the result of calling simulation(args) and simulation does not return a function.