Divide By Mean
- class DivideByMean(filter=<function DivideByMean.<lambda>>)[source]
Bases:
FitnessNormalizer
Divides fitness values by the population mean.
While this function can be used if the fitness value of each
Molecule
in the population is a single number, it is most useful when the fitness value is atuple
of numbers. In this case, it is necessary to somehow combine the numbers so that a single fitness value is produced. For example, take a fitness value which is the vector holding the properties[energy, diameter, num_atoms]
. For a given molecule these numbers may be something like[200,000, 12, 140]
. If we were to sum these numbers, the energy term would dominate the final fitness value. In order to combine these numbers we can divide them by the population averages. For example, if the average energy of molecules in the population is300,000
the average diameter is10
and the average number of atoms is70
then the fitness vector would be scaled to[0.5, 1.2, 2]
. These numbers are now of a similar magnitude and can be summed to give a reasonable value. After division , each value represents how much better than the population average each property value is. In essence we have removed the units from each parameter.Examples
Selectively Normalizing Fitness Values
Sometimes you do not want to normalize all the values in a population together. For example, if a failed fitness value calculation resulted in some records having a fitness value of
None
, you would want to ignore these records from the normalizationimport stk import numpy as np building_block = stk.BuildingBlock( smiles='BrCCBr', functional_groups=[stk.BromoFactory()], ) population = ( stk.MoleculeRecord( topology_graph=stk.polymer.Linear( building_blocks=(building_block, ), repeating_unit='A', num_repeating_units=2, ), ).with_fitness_value( fitness_value=(1., 2., 3.), normalized=False, ), # This will have a fitness value of None. stk.MoleculeRecord( topology_graph=stk.polymer.Linear( building_blocks=(building_block, ), repeating_unit='A', num_repeating_units=2, ), ), ) mean_scaler = stk.DivideByMean( # Only normalize values which are not None. filter=lambda population, record: record.get_fitness_value() is not None ) # Calling mean_scaler.normalize() will return a new # population holding the molecule records with normalized # fitness values. normalized_population = tuple(mean_scaler.normalize( population=population, )) normalized_record1, normalized_record2 = normalized_population assert np.all(np.equal( normalized_record1.get_fitness_value(), (1, 1, 1), ))
Methods
normalize
(population)Normalize the fitness values in population.
- __init__(filter=<function DivideByMean.<lambda>>)[source]
Initialize a
DivideByMean
instance.- Parameters:
filter (
callable
, optional) – Takes two parameters, first is atuple
ofMoleculeRecord
instances, and the second is aMoleculeRecord
. Thecallable
returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. The instance passed to the population argument ofnormalize()
is passed as the first argument, while the second argument will be passed everyMoleculeRecord
in it, one at a time.
- normalize(population)[source]
Normalize the fitness values in population.
- Parameters:
population (
tuple
ofMoleculeRecord
) – The molecules which need to have their fitness values normalized.- Yields:
MoleculeRecord
– A record with a normalized fitness value.