With this example we show one technique for plotting the data of an evolution. As developpers of DEAP we cannot make a choice on what data is important to plot and this part is left to the user. Although, plotting would all occur the same way. First the data is gathered during the evolution and at the end the figures are created from the data. This model is the simplest possible. One could also write all data to a file and read those file again to plot the figures. This later model would be more fault tolerant as if the evolution does not terminate normally, the figures could still be plotted. But, we want to keep this example as simpe as possible and thus we will present the former model.
The beginning of this example is exactly the same as the CMA-ES example. The general evolution loop of function eaGenerateUpdate() is somewhat insufficient for our purpose. We need to gather the required data on each generation. So instead of using the eaGenerateUpdate() function, we’ll develop it to get a grip on what is recorded. First, we’ll created objects to record our data. Here we want to plot, in addition to what the Statistics and HallOfFame objects contain, the step size, the axis ratio and the major axis of the covariace matrix, the best value so far, the best coordinates so far and the standard deviation of the all coordinates at each generation.
sigma = numpy.ndarray((NGEN,1))
axis_ratio = numpy.ndarray((NGEN,1))
diagD = numpy.ndarray((NGEN,N))
fbest = numpy.ndarray((NGEN,1))
best = numpy.ndarray((NGEN,N))
std = numpy.ndarray((NGEN,N))
Once the objects are created, the evolution loop, based on a generational stopping criterion, calls repeatedly the generate(), evaluate() and update() methods registered in the toolbox.
for gen in range(NGEN):
# Generate a new population
population = toolbox.generate()
# Evaluate the individuals
fitnesses = toolbox.map(toolbox.evaluate, population)
for ind, fit in zip(population, fitnesses):
ind.fitness.values = fit
# Update the strategy with the evaluated individuals
toolbox.update(population)
Then, the previoulsy created objects start to play their role. The according data is recorded in each object on each generation.
halloffame.update(population)
stats.update(population)
# Save more data along the evolution for latter plotting
# diagD is sorted and sqrooted in the update method
sigma[gen] = strategy.sigma
axis_ratio[gen] = max(strategy.diagD)**2/min(strategy.diagD)**2
diagD[gen, :N] = strategy.diagD**2
fbest[gen] = halloffame[0].fitness.values
best[gen, :N] = halloffame[0]
Now that the data is recorded the only thing left to do is to plot it. We’ll use matplotlib to generate the graphics from the recorded data.
# The x-axis will be the number of evaluations
x = list(range(0, strategy.lambda_ * NGEN, strategy.lambda_))
plt.figure()
plt.subplot(2, 2, 1)
plt.semilogy(x, stats.avg[0], "--b")
plt.semilogy(x, stats.max[0], "--b")
plt.semilogy(x, stats.min[0], "-b")
plt.semilogy(x, fbest, "-c")
plt.semilogy(x, sigma, "-g")
plt.semilogy(x, axis_ratio, "-r")
plt.grid(True)
plt.title("blue: f-values, green: sigma, red: axis ratio")
plt.subplot(2, 2, 2)
plt.plot(x, best)
plt.grid(True)
plt.title("Object Variables")
plt.subplot(2, 2, 3)
plt.semilogy(x, diagD)
plt.grid(True)
plt.title("Scaling (All Main Axes)")
plt.subplot(2, 2, 4)
plt.semilogy(x, std)
plt.grid(True)
plt.title("Standard Deviations in All Coordinates")
Which gives the following result.