Lab 24: Hardy-Weinberg Equilibrium

BI 255 · Bethune-Cookman University · Fall 2026

Author

Dr. Rosie Stanbrook-Buyer

Published

October 23, 2026


Population Genetics: Are Allele Frequencies in Equilibrium?

The Hardy-Weinberg equilibrium (HWE) is one of the most important theoretical foundations in population genetics. It describes the expected genotype frequencies in a population under a set of idealized conditions — and departures from it reveal forces of evolution at work.

NoteLearning Objectives

By the end of this lab you will be able to:

  1. State the Hardy-Weinberg equilibrium conditions and the HWE equations
  2. Calculate allele frequencies from genotype count data
  3. Calculate expected HWE genotype frequencies from observed allele frequencies
  4. Use a chi-square goodness of fit test to test whether a population is in HWE
  5. Interpret departures from HWE in biological terms (selection, inbreeding, drift)
  6. Apply HWE calculations to a real human genetic disease example

Part 1: The Hardy-Weinberg Principle

For a locus with two alleles (A and a) at frequencies p and q (where p + q = 1), HWE predicts genotype frequencies:

Genotype Expected frequency
AA (homozygous dominant)
Aa (heterozygous) 2pq
aa (homozygous recessive)

These frequencies remain constant from generation to generation if five conditions are met:


HWE conditions (violations drive evolution):

1. Random mating (no mate preference for genotype)
2. No mutation (alleles do not change)
3. No migration (alleles do not enter or leave)
4. No genetic drift (population is infinitely large)
5. No natural selection (all genotypes have equal fitness)

In real populations, at least one condition is usually violated.
Deviations from HWE are therefore evidence for evolutionary forces.

Part 2: Calculating Allele and Genotype Frequencies

# Observed MN blood group data (co-dominant alleles — all three genotypes visible)
# MN blood group in a sample of 1000 people from a Pacific island population
n_MM <- 298    # Homozygous M
n_MN <- 489    # Heterozygous
n_NN <- 213    # Homozygous N
total <- n_MM + n_MN + n_NN

cat("Total individuals:", total, "\n\n")
Total individuals: 1000 
# Step 1: Calculate observed genotype frequencies
freq_MM <- n_MM / total
freq_MN <- n_MN / total
freq_NN <- n_NN / total

cat("Observed genotype frequencies:\n")
Observed genotype frequencies:
cat("  MM:", round(freq_MM, 4), "\n")
  MM: 0.298 
cat("  MN:", round(freq_MN, 4), "\n")
  MN: 0.489 
cat("  NN:", round(freq_NN, 4), "\n\n")
  NN: 0.213 
# Step 2: Calculate allele frequencies from genotype counts
# Count M alleles: 2 per MM individual, 1 per MN individual
alleles_M <- 2 * n_MM + n_MN
alleles_N <- 2 * n_NN + n_MN
total_alleles <- 2 * total

p <- alleles_M / total_alleles   # frequency of M allele
q <- alleles_N / total_alleles   # frequency of N allele

cat("Allele frequencies:\n")
Allele frequencies:
cat("  p (M allele):", round(p, 4), "\n")
  p (M allele): 0.5425 
cat("  q (N allele):", round(q, 4), "\n")
  q (N allele): 0.4575 
cat("  p + q =", round(p + q, 4), "(must equal 1)\n\n")
  p + q = 1 (must equal 1)
# Step 3: Calculate expected HWE frequencies
exp_MM <- p^2 * total
exp_MN <- 2 * p * q * total
exp_NN <- q^2 * total

cat("Expected counts under HWE:\n")
Expected counts under HWE:
cat("  MM:", round(exp_MM, 1), "\n")
  MM: 294.3 
cat("  MN:", round(exp_MN, 1), "\n")
  MN: 496.4 
cat("  NN:", round(exp_NN, 1), "\n")
  NN: 209.3 

Part 3: Testing for HWE with Chi-Square

# Chi-square goodness of fit: observed vs HWE expected
# H₀: population is in Hardy-Weinberg equilibrium
# H₁: population departs from Hardy-Weinberg equilibrium

observed_geno  <- c(MM = n_MM, MN = n_MN, NN = n_NN)
expected_geno  <- c(MM = exp_MM, MN = exp_MN, NN = exp_NN)

# Manual chi-square calculation (instructive)
chi_sq <- sum((observed_geno - expected_geno)^2 / expected_geno)
cat("Chi-square statistic:", round(chi_sq, 4), "\n")
Chi-square statistic: 0.2215 
# Degrees of freedom for HWE test
# df = (number of genotypes - 1) - (number of independently estimated parameters)
# For biallelic locus: df = 3 - 1 - 1 = 1
df_hwe <- 1
p_value <- pchisq(chi_sq, df = df_hwe, lower.tail = FALSE)
cat("df:", df_hwe, "\n")
df: 1 
cat("p-value:", round(p_value, 4), "\n")
p-value: 0.6379 
ImportantWhy df = 1 for HWE?

With three genotype classes, you might expect df = 3 − 1 = 2. However, we estimated one parameter (p) from the data to calculate the expected frequencies. Each estimated parameter costs one degree of freedom. So df = (categories − 1) − (estimated parameters) = 2 − 1 = 1.

This is specific to the HWE test and differs from a standard goodness of fit test where expected proportions are fully specified a priori.

# Visualise observed vs expected
library(ggplot2)

hwe_df <- data.frame(
  Genotype = rep(c("MM", "MN", "NN"), 2),
  Count    = c(observed_geno, expected_geno),
  Type     = rep(c("Observed", "Expected HWE"), each = 3)
)
hwe_df$Genotype <- factor(hwe_df$Genotype, levels = c("MM", "MN", "NN"))

ggplot(hwe_df, aes(x = Genotype, y = Count, fill = Type)) +
  geom_col(position = "dodge", colour = "white") +
  scale_fill_manual(values = c("Observed" = "#2C5F8A", "Expected HWE" = "#A8C4D9")) +
  labs(title    = "MN Blood Group: Observed vs HWE Expected Counts",
       subtitle = paste0("Chi-square = ", round(chi_sq, 2),
                         ", df = 1, p = ", round(p_value, 3)),
       x = "Genotype", y = "Count") +
  theme_classic(base_size = 13)


Part 4: HWE and Human Genetic Disease

The most powerful application of HWE is estimating the carrier frequency of a recessive disease when only affected individuals (homozygous recessives) are identifiable.

# Sickle cell disease (HbS allele)
# Frequency of affected individuals (HbS/HbS) in a West African population: ~2%
# (This is an approximation of real epidemiological data)

q_squared <- 0.02           # frequency of aa (affected)
q_hbs <- sqrt(q_squared)   # frequency of HbS allele
p_hba <- 1 - q_hbs         # frequency of HbA allele

cat("Frequency of HbS allele (q):", round(q_hbs, 4), "\n")
Frequency of HbS allele (q): 0.1414 
cat("Frequency of HbA allele (p):", round(p_hba, 4), "\n\n")
Frequency of HbA allele (p): 0.8586 
# Carrier frequency (HbA/HbS heterozygotes)
carrier_freq <- 2 * p_hba * q_hbs
cat("Expected carrier frequency (2pq):", round(carrier_freq, 4), "\n")
Expected carrier frequency (2pq): 0.2428 
cat("That is approximately 1 in every",
    round(1 / carrier_freq), "individuals.\n\n")
That is approximately 1 in every 4 individuals.
# Full genotype frequency predictions
cat("Predicted genotype frequencies:\n")
Predicted genotype frequencies:
cat("  HbA/HbA (unaffected):", round(p_hba^2, 4), "\n")
  HbA/HbA (unaffected): 0.7372 
cat("  HbA/HbS (carrier):   ", round(carrier_freq, 4), "\n")
  HbA/HbS (carrier):    0.2428 
cat("  HbS/HbS (affected):  ", round(q_hbs^2, 4), "\n")
  HbS/HbS (affected):   0.02 
NoteWhy Sickle Cell Carriers Are Common

In populations with endemic falciparum malaria, HbA/HbS heterozygotes have higher fitness than either homozygote — they are partially protected from malaria without developing sickle cell disease. This is balancing selection (specifically heterozygote advantage / overdominance).

This violates the HWE assumption of no selection, which is exactly why the HbS allele remains at much higher frequency than expected for a lethal recessive in non-malaria regions. Testing for HWE departure can reveal this selection pressure.


Part 5: Interpreting Departures from HWE

# What does each type of departure mean biologically?

# Scenario: excess homozygotes (deficit of heterozygotes)
# Could indicate: inbreeding, population subdivision (Wahlund effect),
# genotyping errors, selection against heterozygotes

# Simulate inbreeding: inbreeding coefficient F
F_inbreeding <- 0.1   # F = 0 is random mating; F = 1 is complete selfing
p_sim <- 0.6
q_sim <- 1 - p_sim

cat("Under inbreeding (F =", F_inbreeding, "):\n")
Under inbreeding (F = 0.1 ):
cat("  Expected AA with inbreeding:", round(p_sim^2 + F_inbreeding * p_sim * q_sim, 4), "\n")
  Expected AA with inbreeding: 0.384 
cat("  Expected Aa with inbreeding:", round(2 * p_sim * q_sim * (1 - F_inbreeding), 4), "\n")
  Expected Aa with inbreeding: 0.432 
cat("  Expected aa with inbreeding:", round(q_sim^2 + F_inbreeding * p_sim * q_sim, 4), "\n\n")
  Expected aa with inbreeding: 0.184 
cat("Under HWE (F = 0):\n")
Under HWE (F = 0):
cat("  Expected AA:", round(p_sim^2, 4), "\n")
  Expected AA: 0.36 
cat("  Expected Aa:", round(2 * p_sim * q_sim, 4), "\n")
  Expected Aa: 0.48 
cat("  Expected aa:", round(q_sim^2, 4), "\n")
  Expected aa: 0.16 

Summary: Causes of HWE departure
----------------------------------
Excess homozygotes (deficit of heterozygotes):
   - Inbreeding / assortative mating
   - Population subdivision (Wahlund effect)
   - Selection against heterozygotes
   - Null alleles (genotyping error)

Excess heterozygotes (deficit of homozygotes):
   - Heterozygote advantage (balancing selection)
   - Recent admixture between populations

Either direction:
   - Genetic drift in small populations
   - Recent selection sweep
   - Population bottleneck

3-Minute Knowledge Check

Close your notes. Answer these on your own — you have 3 minutes. We’ll go through the answers together after.

CautionKnowledge Check Questions

1. A population has 200 AA individuals, 400 Aa, and 400 aa. What are p (frequency of A) and q (frequency of a)?

2. Using the allele frequencies from Question 1, calculate the expected HWE genotype frequencies (as proportions, not counts).

3. A chi-square test of HWE on a biallelic locus gives X² = 8.1, df = 1, p = 0.004. Which statement is most accurate?

a) The population is evolving    b) The data provide evidence that the population departs from HWE    c) Mutation is occurring    d) The population has experienced selection specifically

4. Phenylketonuria (PKU) affects approximately 1 in 10,000 newborns. Assuming HWE, what is the expected carrier frequency?

5. True or False: Under HWE, allele frequencies change from generation to generation but genotype frequencies remain constant.

1. Total individuals = 1000. Total alleles = 2000. A alleles = 2(200) + 400 = 800. a alleles = 2(400) + 400 = 1200. p = 800/2000 = 0.40; q = 1200/2000 = 0.60.

2. HWE expected frequencies: AA = p² = 0.40² = 0.16; Aa = 2pq = 2(0.40)(0.60) = 0.48; aa = q² = 0.60² = 0.36. The observed proportions are 0.20, 0.40, and 0.40 — showing an excess of homozygotes and a deficit of heterozygotes relative to HWE.

3. b) The data provide evidence that the population departs from HWE — A significant chi-square (p = 0.004) means we reject H₀ (HWE). This is evidence for one or more HWE violations (inbreeding, selection, drift, etc.). We cannot conclude specifically that evolution is occurring or which mechanism is responsible from the chi-square test alone.

4. PKU is autosomal recessive. q² = 1/10,000 = 0.0001. q = √0.0001 = 0.01. p = 1 − 0.01 = 0.99. Carrier frequency = 2pq = 2(0.99)(0.01) = 0.0198 ≈ 1 in 50 people are carriers. This illustrates why recessive diseases remain in populations — carriers are far more numerous than affected individuals.

5. False — Under HWE, both allele frequencies and genotype frequencies remain constant from generation to generation. That is the entire point of HWE: the genetic composition of the population is in equilibrium. Neither alleles nor genotypes change in frequency under the five HWE conditions.


Lab 24 Checklist

Before you leave, make sure you can:

TipBonus Challenge

Research the frequencies of the CCR5-delta32 allele in different human populations. This allele confers resistance to HIV infection in homozygotes and partial resistance in heterozygotes. In R, use the published allele frequencies for a European population to calculate expected HWE genotype frequencies. Discuss whether the allele is likely to be under selection and in which direction, based on what you know about its effects.


Before Next Class (Monday, Week 11)

  • Monday (Lab 25): Multiple regression — adding more predictors, model comparison with AIC, and regression diagnostics
  • Today (Friday) is Quiz 6 — covers Labs 21–24