Selection and Mutation–Selection Balance
Natural selection is the deterministic counterpart to genetic drift: instead of allele frequencies wandering by chance, they are pushed in a direction by differences in survival and reproduction. This page shows how to turn genotype fitnesses into an allele-frequency recursion, when that recursion drives an allele to fixation versus maintains a polymorphism, and how recurrent mutation balances selection at a low equilibrium frequency.
Fitness and the selection recursion
Consider a single biallelic locus with alleles and at frequencies and . Assign each genotype a relative fitness — its expected reproductive contribution — writing , , . Starting from Hardy–Weinberg genotype frequencies before selection, the mean fitness of the population is the weighted average Selection reweights each genotype by its fitness, and the frequency of in the next generation is the frequency of -carrying gametes after this reweighting: The change in one generation is The sign of depends only on the bracketed term, and the factor vanishes at the boundaries and , which are always fixed points.
Directional selection
Suppose one homozygote is fittest and the heterozygote is intermediate, for example , , with selection coefficient and dominance coefficient . Then is favoured, for all , and the allele marches monotonically toward fixation at . A recessive deleterious allele () is removed slowly once rare, because selection acts only on the vanishingly few homozygotes.
Overdominance and stable polymorphism
When the heterozygote is fittest — heterozygote advantage, or overdominance — selection maintains both alleles. Write , , with . Setting with requires the bracket to vanish, giving the interior equilibrium This equilibrium is stable: if drifts above the fitter allele becomes the rarer one and selection pushes it back. The textbook case is the sickle-cell allele, where the heterozygote resists malaria while both homozygotes suffer. Frequency-dependent versions of this balancing dynamic are studied in evolutionary game theory.
Mutation–selection balance
A deleterious allele is never fully eliminated because mutation keeps regenerating it. Let mutation from to occur at rate per generation while selection removes . The equilibrium frequency of is where mutational input equals selective removal.
For a fully recessive deleterious allele (, fitness for ), removal near equilibrium is and input is , so For a dominant (or additive) deleterious allele, selection acts on the common heterozygotes, removal is , and The recessive case sits at a much higher frequency for the same and , because deleterious recessives are shielded from selection inside heterozygotes.
Worked example
One generation of directional selection
Take , , and a starting frequency , so . The mean fitness is The updated frequency is So : the favoured allele increases, and iterating this map carries it to fixation.
A mutation–selection balance
Let a recessive lethal-ish allele have with mutation rate . Then If instead the allele were dominant with the same and , its equilibrium would be — a hundredfold lower.
Simulation
Iterate the selection recursion from a starting frequency and watch it approach fixation (directional) or an interior equilibrium (overdominance).
R
selection_step <- function(p, wAA, wAa, waa) {
q <- 1 - p
wbar <- p^2 * wAA + 2 * p * q * wAa + q^2 * waa
(p^2 * wAA + p * q * wAa) / wbar
}
iterate <- function(p0, wAA, wAa, waa, gens = 200) {
p <- p0
for (i in seq_len(gens)) p <- selection_step(p, wAA, wAa, waa)
p
}
# Directional: A fixes
iterate(0.3, 1.0, 0.9, 0.8) # ~ 1.0 (fixation of A)
# Overdominance: stable polymorphism, phat = s2/(s1+s2)
s1 <- 0.2; s2 <- 0.3
iterate(0.05, 1 - s1, 1, 1 - s2) # ~ 0.6 = 0.3/0.5
Python
import numpy as np
def selection_step(p, wAA, wAa, waa):
q = 1 - p
wbar = p**2 * wAA + 2 * p * q * wAa + q**2 * waa
return (p**2 * wAA + p * q * wAa) / wbar
def iterate(p0, wAA, wAa, waa, gens=200):
p = p0
for _ in range(gens):
p = selection_step(p, wAA, wAa, waa)
return p
# Directional: A fixes
print(iterate(0.3, 1.0, 0.9, 0.8)) # ~ 1.0
# Overdominance: stable polymorphism at s2/(s1+s2)
s1, s2 = 0.2, 0.3
print(iterate(0.05, 1 - s1, 1, 1 - s2)) # ~ 0.6
0.9999999985559945
0.5999999999998405
Julia
function selection_step(p, wAA, wAa, waa)
q = 1 - p
wbar = p^2*wAA + 2p*q*wAa + q^2*waa
(p^2*wAA + p*q*wAa) / wbar
end
function iterate_sel(p0, wAA, wAa, waa; gens=200)
p = p0
for _ in 1:gens
p = selection_step(p, wAA, wAa, waa)
end
p
end
iterate_sel(0.3, 1.0, 0.9, 0.8) # ~ 1.0 (fixation)
s1, s2 = 0.2, 0.3
iterate_sel(0.05, 1 - s1, 1, 1 - s2) # ~ 0.6
Why it matters
Selection is the engine of adaptation, and this simple recursion is the workhorse that turns genotype fitnesses into predictions about how populations change. It explains why some alleles sweep to fixation while others persist as protected polymorphisms, and mutation–selection balance sets the baseline burden of deleterious variation that every population carries — the quantity behind genetic load, the maintenance of disease alleles, and the evolution of dominance.