A crossover operator defines how two individuals should be combined to create a new individual (or individuals). Importantly, the crossover operator allows for the preservation of preferable characteristics found by the genetic algorithm.
In EDO, the crossover operator returns exactly one individual from a pair of parents. As is discussed elsewhere_, an individual is created by sampling its dimensions and then its values. Creating an offspring is done in the same way except it inherits these characteristics from its parents:
- Inherit a number of rows and a number of columns from either parent, independently and uniformly. This is the skeleton of the dataset.
- Pool together the columns (and respective column distributions) from both parents.
- Sample from this pool uniformly (and without replacement) to fill in the columns of the offspring’s dataset. Now the dataset has values and instructions on how to manipulate it.
- Remove surplus rows as required, and fill in any missing values using the corresponding column information. This is now a complete individual.
Before this offspring is added to population, it must undergo mutation.
Consider the following example where two individuals are created:
>>> import numpy as np >>> from edo import Family >>> from edo.distributions import Poisson >>> from edo.individual import create_individual >>> from edo.operators import crossover >>> >>> row_limits, col_limits = [1, 3], [2, 3] >>> families = [Family(Poisson)] >>> states = [np.random.RandomState(i) for i in range(2)] >>> >>> parents = [ ... create_individual( ... row_limits, col_limits, families, weights=None, random_state=state ... ) for state in states ... ]
These individuals’ dataframes look like this:
>>> parents.dataframe 0 1 2 0 12 0 12 >>> parents.dataframe 0 1 2 0 0 5 7 1 4 4 9
And their metadata like this:
>>> parents.metadata [Poisson(lam=7.15), Poisson(lam=0.87), Poisson(lam=8.33)] >>> parents.metadata [Poisson(lam=7.2), Poisson(lam=3.97), Poisson(lam=8.01)]
Now, we create a PRNG for the offspring and apply the crossover:
>>> state = np.random.RandomState(2) >>> offspring = crossover(*parents, col_limits, families, state) >>> >>> offspring.dataframe 0 1 2 0 0 12 7 >>> offspring.metadata [Poisson(lam=7.2), Poisson(lam=8.33), Poisson(lam=8.01)]