Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Documentación: link.
Algoritmo
Aunque existen variaciones, algunas de las cuales se describen a lo largo de este
documento, en términos generales, la estructura de un algoritmo genético para
optimizar (maximizar o minimizar) una función con una o múltiples variables sigue
los siguientes pasos:
Crear una nueva población vacía y repetir los siguientes pasos hasta que se hayan
creado P nuevos individuos.
3.2 Cruzar los dos individuos seleccionados para generar un nuevo descendiente
(crossover).
En los siguientes apartados se describe cada una de las etapas del algoritmo.
Población
En el contexto de algoritmos genéticos, el término individuo hace referencia a cada
una de las posibles soluciones del problema que se quiere resolver. En el caso de
maximización o minimización de una función, cada individuo representa una posible
combinación de valores de las variables. Para representar dichas combinaciones, se
pueden emplear vectores (arrays), cuya longitud es igual al número total de
variables, y cada posición toma un valor numérico. Por ejemplo, supóngase que la
función objetivo J(x,y,z) depende de las variables x,y,z . El individuo
3.0,9.5,−0.5 , equivale a la combinación de valores x=3.0,y=9.5,z=−0.5 .
Fitness
Cada individuo de la población debe ser evaluado para cuantificar cómo de bueno es
como solución al problema, a esta cuantificación se le llama (fitness). Dependiendo
de si se trata de un problema de maximización o minimización, la relación del
fitness con la función objetivo f puede ser:
Seleccionar individuos
La forma en que se seleccionan los individuos que participan en cada cruce difiere
en las distintas implementaciones de los algoritmos genéticos. Por lo general,
todas ellas tienden a favorecer la selección de aquellos individuos con mayor
fitness. Algunas de las estrategias más comunes son:
Cruzamiento uniforme: el valor que toma cada posición del nuevo individuo se
obtiene de uno de los dos parentales. Por lo general, la probabilidad de que el
valor proceda de cada parental es la misma, aunque podría, por ejemplo, estar
condicionada al fitness de cada uno. A diferencia de las anteriores estrategias,
con esta, de cada cruce se genera un único descendiente.
Mutar individuo
Tras generar cada nuevo individuo de la descendencia, este se somete a un proceso
de mutación en el que, cada una de sus posiciones, puede verse modificada con una
probabilidad p . Este paso es importante para añadir diversidad al proceso y
evitar que el algoritmo caiga en mínimos locales por que todos los individuos sean
demasiado parecidos de una generación a otra.
Existen diferentes estrategias para controlar la magnitud del cambio que puede
provocar una mutación.
Hay que tener en cuenta que, debido a las mutaciones, un valor que inicialmente
estaba dentro del rango permitido puede salirse de él. Una forma de evitarlo es: si
el valor tras la mutación excede alguno de los límites acotados, se sobrescribe con
el valor del límite. Es decir, se permite que los valores se alejen como máximo
hasta el límite impuesto.
Implementación python
################################################################################
# LIBRERÍAS NECESARIAS
################################################################################
import numpy as np
import random
import warnings
import random
import copy
import pandas as pd
import time
from datetime import datetime
Clase Individuo
################################################################################
# CÓDIGO OPTIMIZACIÓN CON ALGORITMO GENÉTICO #
# #
# This work by Joaquín Amat Rodrigo is licensed under a Creative Commons #
# Attribution 4.0 International License. #
################################################################################
# coding=utf-8
################################################################################
# CLASE INDIVIDUO #
################################################################################
class Individuo:
"""
Esta clase representa un individuo con unas características inicial definida
por una combinación de valores numéricos aleatorios. El rango de posibles
valores para cada variable puede estar acotado.
Parameters
----------
n_variables : `int`
número de variables que definen al individuo.
Attributes
----------
n_variables : `int`
número de variables que definen al individuo.
valor_variables : `numpy.ndarray`
array con el valor de cada una de las variables.
fitness : `float`
valor de fitness del individuo.
valor_funcion : `float`
valor de la función objetivo para el individuo.
Raises
------
raise Exception
si `limites_inf` es distinto de None y su longitud no coincide con
`n_variables`.
raise Exception
si `limites_sup` es distinto de None y su longitud no coincide con
`n_variables`.
Examples
--------
Ejemplo creación individuo.
"""
def __repr__(self):
"""
Información que se muestra cuando se imprime un objeto individuo.
"""
texto = "Individuo" \
+ "\n" \
+ "---------" \
+ "\n" \
+ "Valor variables: " + str(self.valor_variables) \
+ "\n" \
+ "Valor función objetivo: " + str(self.valor_funcion) \
+ "\n" \
+ "Fitness: " + str(self.fitness) \
+ "\n" \
+ "Límites inferiores de cada variable: " \
+ str(self.limites_inf) \
+ "\n" \
+ "Límites superiores de cada variable: " \
+ str(self.limites_sup) \
+ "\n"
return(texto)
Parameters
----------
funcion_objetivo : `function`
función que se quiere optimizar.
Raises
------
raise Exception
si el argumento `optimizacion` es distinto de 'maximizar' o
'minimizar'
Notes
-----
Examples
--------
Ejemplo evaluar individuo con una función objetivo.
>>> individuo.calcular_fitness(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
"""
Raises
------
raise Exception
si el argumento `distribucion` es distinto de 'normal', 'uniforme' o
'aleatoria'.
Examples
--------
Ejemplo mutar individuo.
>>> individuo.mutar(
prob_mut = 0.5,
distribucion = "uniforme",
min_distribucion = -1,
max_distribucion = 1,
verbose = True
)
Notes
-----
Hay que tener en cuenta que, debido a las mutaciones, un valor que
inicialmente estaba dentro del rango permitido puede salirse de él.
Una forma de evitarlo es: si el valor tras la mutación excede alguno de
los límites acotados, se sobrescribe con el valor del límite. Es decir,
se permite que los valores se alejen como máximo hasta el límite impuesto.
"""
################################################################################
# CLASE POBLACIÓN #
################################################################################
class Poblacion:
"""
Esta clase crea una población de n individuos.
Parameters
----------
n_individuos :`int`
número de individuos de la población.
n_variables : `int`
número de variables que definen a cada individuo.
Attributes
----------
individuos : `list`
lista con todos los individuos de la población en su estado actual.
n_individuos :`int`
número de individuos de la población.
n_variables : `int`
número de variables que definen a cada individuo.
mejor_fitness : `float`
fitness del mejor individuo de la población en su estado actual.
mejor_valor_funcion : `float`
valor de la función objetivo del mejor individuo de la población en su
estado actual.
mejor_individuo_variables : `numpy.ndarray`
valor de las variables del mejor individuo de la población en su estado
actual.
historico_individuos : `list`
lista con la información de todos los individuos en cada una de las
generaciones que ha tenido la población.
historico_mejor_individuo_variables : `list`
lista con valor de las variables del mejor individuo en cada una de las
generaciones que ha tenido la población.
historico_mejor_fitness : `list`
lista con el mejor fitness en cada una de las generaciones que ha tenido
la población.
historico_mejor_valor_funcion : `list`
lista con valor de la función objetivo del mejor individuo en cada una
de las generaciones que ha tenido la población.
diferencia_abs : `list`
diferencia absoluta entre el mejor fitness de generaciones consecutivas.
resultados_df : `pandas.core.frame.DataFrame`
dataframe con la información del mejor fitness y valor de las variables
encontrado en cada generación, así como la diferencia respecto a la
generación anterior.
fitness_optimo : `float`
mejor fitness encontrado tras el proceso de optimización.
valor_funcion_optimo : `float`
valor de la función objetivo encontrado tras el proceso de optimización.
valor_variables_optimo : `numpy.narray`
valor de las variables con el que se ha conseguido el mejor fitness tras
el proceso de optimización.
optimizado : `bool`
si la población ha sido optimizada.
iter_optimizacion : `int`
número de iteraciones de optimización (generaciones).
Examples
--------
Ejemplo crear población
"""
def __repr__(self):
"""
Información que se muestra cuando se imprime un objeto población.
"""
texto = "============================" \
+ "\n" \
+ " Población" \
+ "\n" \
+ "============================" \
+ "\n" \
+ "Número de individuos: " + str(self.n_individuos) \
+ "\n" \
+ "Límites inferiores de cada variable: " + str(self.limites_inf) \
+ "\n" \
+ "Límites superiores de cada variable: " + str(self.limites_sup) \
+ "\n" \
+ "Optimizado: " + str(self.optimizado) \
+ "\n" \
+ "Iteraciones optimización (generaciones): " \
+ str(self.iter_optimizacion) \
+ "\n" \
+ "\n" \
+ "Información del mejor individuo:" \
+ "\n" \
+ "----------------------------" \
+ "\n" \
+ "Valor variables: " + str(self.mejor_valor_variables) \
+ "\n" \
+ "Fitness: " + str(self.mejor_fitness) \
+ "\n" \
+ "\n" \
+ "Resultados tras optimizar:" \
+ "\n" \
+ "--------------------------" \
+ "\n" \
+ "Valor óptimo de variables: " +
str(self.valor_variables_optimo) \
+ "\n" \
+ "Valor óptimo función objetivo: " +
str(self.valor_funcion_optimo) \
+ "\n" \
+ "Fitness óptimo: " + str(self.fitness_optimo)
return(texto)
Parameters
----------
n : `int`
número de individuos que se muestran. Si no se indica el valor
(por defecto ``None``), se muestran todas. Si el valor es mayor
que `self.n_individuos` se muestran todas.
Examples
--------
>>> poblacion = Poblacion(
n_individuos = 5,
n_variables = 3,
limites_inf = [-5,-5,-5],
limites_sup = [5,5,5],
verbose = True
)
>>> poblacion.mostrar_individuos(n = 1)
"""
if n is None:
n = self.n_individuos
elif n > self.n_individuos:
n = self.n_individuos
for i in np.arange(n):
print(self.individuos[i])
return(None)
Parameters
----------
funcion_objetivo : `function`
función que se quiere optimizar.
Examples
--------
Ejemplo evaluar población
>>> poblacion.evaluar_poblacion(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
"""
parental_1 : `int`
índice del individuo de la población que se quiere emplear como
parental 1 para el cruzamiento.
Raises
------
raise Exception
si los índices parental_1 o parental_2 no son índices válidos.
Returns
------
descendencia : `Individuo`
Nuevo individuo generado por cruzamiento de dos parentales.
Examples
--------
>>> poblacion = Poblacion(
n_individuos = 5,
n_variables = 3,
limites_inf = [-5,-5,-5],
limites_sup = [5,5,5]
)
Notes
-----
El objetivo del cruzamiento es generar, a partir de individuos ya
existentes (parentales), nuevos individuos (descendencia) que combinen
las características de los anteriores. Este es otro de los puntos del
algoritmo en los que se puede seguir varias estrategias. Tres de las más
empleadas son:
"""
# CREACIÓN DE LA DESCENDENCIA
# ----------------------------------------------------------------------
# Se extraen los parentales acorde a los índices indicados.
parental_1 = self.individuos[parental_1]
parental_2 = self.individuos[parental_2]
# Se clona uno de los parentales para utilizarlo como plantilla del nuevo
# individuo.
descendencia = copy.deepcopy(parental_1)
descendencia.valor_variables = np.repeat(None, descendencia.n_variables)
descendencia.fitness = None
descendencia.valor_variables[herencia_parent_2] \
= parental_2.valor_variables[herencia_parent_2]
Parameters
----------
n : `int`
número de individuos de la población seleccionados.
Raises
------
raise Exception
si el argumento `metodo_seleccion` no es 'ruleta', 'rank' o
'tournament'.
Returns
-------
indices : `numpy.ndarray`
índice de los individuos seleccionados (si `return_indices=True`).
individuos : `list`
lista con los individuos seleccionados (si `return_indices=False`).
Examples
--------
>>> poblacion = Poblacion(
n_individuos = 5,
n_variables = 3,
limites_inf = [-5,-5,-5],
limites_sup = [5,5,5],
verbose = True
)
>>> poblacion.evaluar_poblacion(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
>>> poblacion.seleccionar_individuo(
n = 2,
return_indices = True,
metodo_seleccion = "tournament",
verbose = True
)
Notes
-----
La forma en que se seleccionan los individuos que participan en cada cruce
difiere en las distintas implementaciones de los algoritmos genéticos.
Por lo general, todas ellas tienden a favorecer la selección de aquellos
individuos con mayor fitness. Algunas de las estrategias más comunes son:
"""
# SELECCIÓN DE INDIVIDUOS
# ----------------------------------------------------------------------
# Se crea un array con el fitness de cada individuo de la población.
array_fitness = np.repeat(None, self.n_individuos)
for i in np.arange(self.n_individuos):
array_fitness[i] = copy.copy(self.individuos[i].fitness)
if(return_indices):
return(ind_seleccionado)
else:
if n == 1:
return(copy.deepcopy(self.individuos[int(ind_seleccionado)]))
if n > 1:
return(
[copy.deepcopy(self.individuos[i]) for i in ind_seleccionado]
)
Parameters
----------
metodo_seleccion : {"ruleta", "rank", "tournament"}
método de selección de selección, ver notas para más información.
(default `tournament`)
Examples
--------
>>> poblacion.evaluar_poblacion(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
>>> poblacion.crear_nueva_generecion(
metodo_seleccion = "tournament",
elitismo = 0.1,
prob_mut = 0.01,
distribucion = "uniforme",
verbose = True,
verbose_seleccion = False,
verbose_cruce = False,
verbose_mutacion = False
)
"""
Parameters
----------
funcion_objetivo : `function`
función que se quiere optimizar.
Raises
------
raise Exception
si se indica `parada_temprana = True` y los argumentos `rondas_parada`
o `tolerancia_parada` son ``None``.
raise Exception
si el argumento `metodo_seleccion` no es 'ruleta', 'rank' o
'tournament'.
raise Exception
si el argumento `optimizacion` es distinto de 'maximizar' o
'minimizar
Examples
--------
Ejemplo optimización
>>> poblacion.optimizar(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
n_generaciones = 250,
metodo_seleccion = "tournament",
elitismo = 0.1,
prob_mut = 0.01,
distribucion = "uniforme",
media_distribucion = 1,
sd_distribucion = 1,
min_distribucion = -1,
max_distribucion = 1,
parada_temprana = True,
rondas_parada = 10,
tolerancia_parada = 10**-16,
verbose = False
)
"""
# ITERACIONES (GENERACIONES)
# ----------------------------------------------------------------------
start = time.time()
for i in np.arange(n_generaciones):
if verbose:
print("-------------")
print("Generación: " + str(i))
print("-------------")
# CRITERIO DE PARADA
# ------------------------------------------------------------------
# Si durante las últimas n generaciones, la diferencia absoluta entre
# mejores individuos no es superior al valor de tolerancia_parada,
# se detiene el algoritmo y no se crean nuevas generaciones.
if parada_temprana and i > rondas_parada:
ultimos_n = np.array(self.diferencia_abs[-(rondas_parada): ])
if all(ultimos_n < tolerancia_parada):
print("Algoritmo detenido en la generación "
+ str(i) \
+ " por falta cambio absoluto mínimo de " \
+ str(tolerancia_parada) \
+ " durante " \
+ str(rondas_parada) \
+ " generaciones consecutivas.")
break
self.crear_nueva_generecion(
metodo_seleccion = metodo_seleccion,
elitismo = elitismo,
prob_mut = prob_mut,
distribucion = distribucion,
verbose = verbose_nueva_generacion,
verbose_seleccion = verbose_seleccion,
verbose_cruce = verbose_cruce,
verbose_mutacion = verbose_mutacion
)
end = time.time()
self.optimizado = True
self.iter_optimizacion = i
.historico_mejor_valor_funcion[indice_valor_optimo]
self.valor_variables_optimo = self\
.historico_mejor_valor_variables[indice_valor_optimo]
print("-------------------------------------------")
print("Optimización finalizada " \
+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
print("-------------------------------------------")
print("Duración optimización: " + str(end - start))
print("Número de generaciones: " + str(self.iter_optimizacion))
print("Valor óptimo de las variables: " + str(self.valor_variables_optimo))
print("Valor función objetivo: " + str(self.valor_funcion_optimo))
print("")
Ejemplos
%matplotlib inline
# Para que las imágenes se muestren en el centro de la celda.
from IPython.core.display import HTML
HTML("""
<style>
.output_png {
display: table-cell;
text-align: center;
vertical-align: middle;
}
</style>
""")
Crear individuo
individuo = Individuo(
n_variables = 3,
limites_inf = [-1,2,0],
limites_sup = [4,10,20],
verbose = True
)
Nuevo individuo creado
----------------------
Valor variables: [2.7499135795114786 9.419114099219769 14.950239339953148]
Valor función objetivo: None
Fitness: None
Límites inferiores de cada variable: [-1 2 0]
Límites superiores de cada variable: [ 4 10 20]
individuo.calcular_fitness(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
El individuo ha sido evaluado
-----------------------------
Valor función objetivo: 319.791391430785
Fitness: -319.791391430785
Mutar individuo
individuo.mutar(
prob_mut = 0.5,
distribucion = "uniforme",
min_distribucion = -1,
max_distribucion = 1,
verbose = True
)
El individuo ha sido mutado
---------------------------
Total mutaciones: 2
Valor variables: [2.7499135795114786 8.934210068569826 14.024387157926302]
Crear Población
poblacion = Poblacion(
n_individuos = 3,
n_variables = 3,
limites_inf = [-5,-5,-5],
limites_sup = [5,5,5],
verbose = True
)
Nuevo individuo creado
----------------------
Valor variables: [-4.6712501773550175 1.5587942254340064 0.07546635543250435]
Valor función objetivo: None
Fitness: None
Límites inferiores de cada variable: [-5 -5 -5]
Límites superiores de cada variable: [5 5 5]
----------------
Población creada
----------------
Número de individuos: 3
Límites inferiores de cada variable: [-5 -5 -5]
Límites superiores de cada variable: [5 5 5]
Individuo
---------
Valor variables: [0.9722817522602902 -4.456082464908084 3.3040857874193286]
Valor función objetivo: None
Fitness: None
Límites inferiores de cada variable: [-5 -5 -5]
Límites superiores de cada variable: [5 5 5]
Evaluar población
def funcion_objetivo(x_0, x_1, x_2):
f= x_0**2 + x_1**2 + x_2**2
return(f)
poblacion.evaluar_poblacion(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
verbose = True
)
El individuo ha sido evaluado
-----------------------------
Valor función objetivo: 24.25611282748795
Fitness: -24.25611282748795
------------------
Población evaluada
------------------
Mejor fitness encontrado : -24.25611282748795
Valor de la función objetivo: 24.25611282748795
Mejor valor de variables encontrado : [-4.6712501773550175 1.5587942254340064
0.07546635543250435]
Seleccionar individuos
poblacion.seleccionar_individuo(
n = 2,
return_indices = True,
metodo_seleccion = "tournament",
verbose = True
)
---------------
Individuo seleccionado
---------------
Método selección: tournament
Se compara el patrón de selección del mejor individuo entre los métodos ruleta,
rank y tournament. En primer lugar, se muestra un caso en el que la diferencia
entre el mayor y el menor de los fitness no es muy acusada, y un segundo caso en el
que sí lo es.
import matplotlib
import matplotlib.pyplot as plt
array_fitness = np.array([20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7,
6, 5, 4, 3, 2, 1])
order = np.flip(np.argsort(a=array_fitness) + 1)
ranks = np.argsort(order) + 1
probabilidad_seleccion = 1 / ranks
probabilidad_seleccion = probabilidad_seleccion / np.sum(probabilidad_seleccion)
ind_seleccionado = np.random.choice(
a = np.arange(len(array_fitness)),
size = 500,
p = list(probabilidad_seleccion),
replace = True
)
pd.value_counts(pd.Series(ind_seleccionado)).plot(kind="bar",
ylim=(0,200),
title = "Rank",
ax = axs[1])
indices_seleccionados = np.repeat(None,500)
for i in np.arange(500):
# Se seleccionan aleatoriamente dos parejas de individuos.
candidatos_a = np.random.choice(
a = np.arange(len(array_fitness)),
size = 2,
replace = False
)
candidatos_b = np.random.choice(
a = len(array_fitness),
size = 2,
replace = False
)
# De cada pareja se selecciona el de mayor fitness.
if array_fitness[candidatos_a[0]] > array_fitness[candidatos_a[1]]:
ganador_a = candidatos_a[0]
else:
ganador_a = candidatos_a[1]
indices_seleccionados[i] = ind_seleccionado
pd.value_counts(pd.Series(indices_seleccionados)).plot(kind="bar",
ylim=(0,200),
title = "Tournament",
ax=axs[2])
<matplotlib.axes._subplots.AxesSubplot at 0x7f2e60356cc0>
array_fitness = np.array([200, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7,
6, 5, 4, 3, 2, 1])
indices_seleccionados = np.repeat(None,500)
for i in np.arange(500):
# Se seleccionan aleatoriamente dos parejas de individuos.
candidatos_a = np.random.choice(
a = np.arange(len(array_fitness)),
size = 2,
replace = False
)
candidatos_b = np.random.choice(
a = len(array_fitness),
size = 2,
replace = False
)
# De cada pareja se selecciona el de mayor fitness.
if array_fitness[candidatos_a[0]] > array_fitness[candidatos_a[1]]:
ganador_a = candidatos_a[0]
else:
ganador_a = candidatos_a[1]
indices_seleccionados[i] = ind_seleccionado
pd.value_counts(pd.Series(indices_seleccionados)).plot(kind="bar",
ylim=(0,200),
title = "Tournament",
ax=axs[2])
<matplotlib.axes._subplots.AxesSubplot at 0x7f2e60138208>
Cuando existe una gran diferencia entre el individuo de mayor fitness y el resto
(uno o varios órdenes de magnitud), con el método ruleta, el individuo con mayor
fitness se selecciona con mucha más frecuencia que el resto. A diferencia del caso
anterior, en esta situación, la probabilidad de selección decae de forma más
gradual con los métodos rank y tournament.
Teniendo en cuenta los comportamientos de selección de cada método, el método
tournament parece ser la opción más equilibrada independientemente de la
distribución de los fitness.
Cruzar individuos
descendencia = poblacion.cruzar_individuos(
parental_1 = 0,
parental_2 = 1,
verbose = True
)
------------------------------------
Cruce realizado: descendencia creada
------------------------------------
Valor variables: [-4.6712501773550175 -4.456082464908084 3.3040857874193286]
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
fig = plt.figure(figsize=(8.5, 6))
ax = fig.add_subplot(111, projection='3d')
# Grid de datos
x = np.arange(-10, 0, 0.05)
y = np.arange(-6.5, 0, 0.05)
x, y = np.meshgrid(x, y)
z = np.array(funcion_objetivo(np.ravel(x), np.ravel(y)))
z = z.reshape(x.shape)
ax.view_init(30, 45)
poblacion = Poblacion(
n_individuos = 50,
n_variables = 2,
limites_inf = [-10, -6.5],
limites_sup = [0, 0],
verbose = False
)
poblacion.optimizar(
funcion_objetivo = funcion_objetivo,
optimizacion = "minimizar",
n_generaciones = 250,
metodo_seleccion = "tournament",
elitismo = 0.1,
prob_mut = 0.01,
distribucion = "uniforme",
media_distribucion = 1,
sd_distribucion = 1,
min_distribucion = -1,
max_distribucion = 1,
parada_temprana = True,
rondas_parada = 10,
tolerancia_parada = 10**-16,
verbose = False
)
Algoritmo detenido en la generación 14 por falta cambio absoluto mínimo de 1e-16
durante 10 generaciones consecutivas.
-------------------------------------------
Optimización finalizada 2019-05-19 16:40:19
-------------------------------------------
Duración optimización: 0.564697265625
Número de generaciones: 14
Valor óptimo de las variables: [-3.100717163284904 -1.6339872148045957]
Valor función objetivo: -106.58214810361343
# Evolución de la optimización
plt.style.use('ggplot')
fig, ax = plt.subplots()
poblacion.resultados_df.plot(x = "generacion",
y = "mejor_fitness",
ax= ax)
ax.set(title='Evolución del mejor Individuo', xlabel='generacion',
ylabel='fitness')
ax.legend().set_visible(False)
def extraer_posicion(individuo):
posicion = individuo.valor_variables
return(posicion)
lista_df_temp = []
for i in np.arange(len(poblacion.historico_individuos)):
posiciones = list(map(extraer_posicion, poblacion.historico_individuos[i]))
df_temp = pd.DataFrame({"generacion": i, "posicion": posiciones})
lista_df_temp.append(df_temp)
df_posiciones = pd.concat(lista_df_temp)
df_posiciones[['x_0','x_1']] =
pd.DataFrame(df_posiciones["posicion"].values.tolist(),
index= df_posiciones.index)
df_posiciones.head()
generacion posicion x_0 x_1
0 0 [-9.600984144843466, -0.3972809848944241] -9.600984 -0.397281
1 0 [-5.742229696011667, -2.177043043122727] -5.742230 -2.177043
2 0 [-3.24811808697644, -2.0929817577917014] -3.248118 -2.092982
3 0 [-8.645498582852397, -1.630055397953189] -8.645499 -1.630055
4 0 [-3.0607128338459786, -1.9988087338751388] -3.060713 -1.998809
px.scatter(
df_posiciones,
x = "x_0",
y = "x_1",
range_x = [-10, 0],
range_y = [-6.5, 0],
animation_frame = "generacion"
)
−10
−8
−6
−4
−2
0
−6
−5
−4
−3
−2
−1
0
x_0
x_1
Con la extensión matplotlib.animation se puede crear un gift animationnimado.
#def animate(i):
# p2 = fig.clear()
# plt.xlim(-10,0)
# plt.ylim(-6.5,0)
# df_posiciones_i = df_posiciones[df_posiciones["generacion"] == i][["x_0",
"x_1"]]
# p1 = plt.contour(x_0, x_1, z, 35, cmap='RdGy')
# p2 = plt.scatter(df_posiciones_i["x_0"], df_posiciones_i["x_1"])
Durand, Nicolas & Alliot, Jean-Marc. (1999). A Combined Nelder-Mead Simplex and
Genetic Algorithm.
wikipedia.org/wiki/Genetic_algorithm.
wikipedia.org/wiki/Crossover_(genetic_algorithm).
https://www.sfu.ca/~ssurjano/optimization.html.