DEAP1.2.2(六) 一个GP实例——用于函数发现

(六) GP实例——函数发现
话不多说直接上代码

import operator, math, random, numpy
from deap import gp, tools, base, creator, algorithms

toolbox = base.Toolbox()
pset = gp.PrimitiveSet("MAIN", 1)
#define protectedDive function which return their division
def protectedDiv(left, right):
    try:
        return left / right
    except ZeroDivisionError:
        return 1
#adding other functions
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(operator.mul, 2)
pset.addPrimitive(protectedDiv, 2)
pset.addPrimitive(operator.neg, 1)
pset.addPrimitive(math.cos, 1)
pset.addPrimitive(math.sin, 1)
#add random constants which is an int type
pset.addEphemeralConstant("rand1", lambda: random.randint(-1,1))
#rename augument x
pset.renameArguments(ARG0='x')

#creating MinFit 
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
#creating individual
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMin)

#import toolbox
toolbox = base.Toolbox()
#resigter expr individual population and compile
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)     #0~3
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("compile", gp.compile, pset=pset)
#define evaluating function
def evalSymbReg(individual, points):
    # Transform the tree expression in a callable function
    func = toolbox.compile(expr=individual)
    # Evaluate the mean squared error between the expression
    # and the real function : x**4 + x**3 + x**2 + x
    sqerrors = ((func(x) - x**4 - x**3 - x**2 - x)**2 for x in points) #define their differential
    #return the average fitness
    return math.fsum(sqerrors) / len(points),

#register genetic operations(evaluate/selection/mutate/crossover/)
toolbox.register("evaluate", evalSymbReg, points=[x/10. for x in range(-10,10)]) #the range of points in evaluate function
toolbox.register("select", tools.selTournament, tournsize=3) 
toolbox.register("mate", gp.cxOnePoint)\
#this is expr_mut, if we want to use a GEP, we can mutute the expr at first, then do the expression
toolbox.register("expr_mut", gp.genFull, min_=0, max_=2)
toolbox.register("mutate", gp.mutUniform, expr=toolbox.expr_mut, pset=pset)
#decorating the operator including crossover and mutate, restricting the tree's height and length
toolbox.decorate("mate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))
toolbox.decorate("mutate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))

def main():
    #Parameter setting
    CXPB = 0.1
    MUPB = 0.1
    GEN = 400
    POP_SIZE = 300 
    #initializing population
    pop = toolbox.population(n = POP_SIZE)
    
    '''start evolution'''
    print('Start evolution')
    #evaluating the fitness
    fitnesses = list(map(toolbox.evaluate, pop))
    #assign fitness values
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit
    print('Evaluated %i individuals' %len(pop))
    '''The genetic operations'''
    for g in range(GEN):
        #select
        offspring = toolbox.select(pop, len(pop))
        offspring = list(map(toolbox.clone, offspring))
        #crossover
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if random.random() < CXPB:
                toolbox.mate(child1, child2)
                
                del child1.fitness.values
                del child2.fitness.values
        
        #mutation
        for mutant in offspring:
            if random.random() < MUPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values
        
        #evaluate the invalid individuals
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = list(map(toolbox.evaluate, invalid_ind))
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit
        print('Evaluated %i individuals' %len(invalid_ind))
        
        #update the pop
        pop[:] = offspring
        
        #statistics
        stats = tools.Statistics(key=lambda ind: ind.fitness.values)
        record = stats.compile(pop)
        stats.register("avg", numpy.mean, axis=0)
        stats.register("min", numpy.min, axis=0)
        stats.register("max", numpy.max, axis=0)
        record = stats.compile(pop)
        logbook = tools.Logbook()
        logbook.record(gen=g, evals=30, **record)
        logbook.header = "gen", "avg", "min", "max"
        print(logbook)
        


    print("-- End of (successful) evolution --")
    
    best_ind = tools.selBest(pop, 1)[0]
    print("Best individual is %s, Best results are %s" % (best_ind, best_ind.fitness.values))
    
        
    

if __name__ == "__main__":
    main()

大部分注释都有写,总结一下这个例子:
首先,要发现的函数是: f(x) = x^4 - x^3 - x^2 - x, fitness func为 min{sum(func(x) - f(x))^2}/xnum,x in (-1, 1] 间隔0.1。
接下来首先搭建GP框架
STEP1. 适应度函数的构建,个体及种群初始化,所用工具包:creator/toolbox
STEP2. 演化操作定义以及树的size限制
STEP3. 设定参数(交叉率、变异率、迭代次数以及种群大小),初始化种群并计算适应度
STEP4. 按照选择、交叉、变异的顺序进行演化操作,在一次演化操作完成后选出无效个体(即适应性不如先前个体的个体,对这些个体的适应度不予修改)
STEP5. 更新种群,统计当前种群的适应度信息并输出
STEP6. 当循环结束,输出全局最优解

注意:在GP这种树结构的算法中,在适应度计算当中,生成的树结构首先要通过toolbox.compile转化为函数,再通过函数进行计算,同时所有的遗传操作均是基于树结构进行的,因此在register这些步骤时候需要使用特定的方法,如gp.cxOnePoint等。

你可能感兴趣的:(DEAP1.2.2(六) 一个GP实例——用于函数发现)