Équilibre des fréquences alléliques · Démonstration mathématique · Simulation
Au début du XXe siècle, les biologistes redécouvrent les lois de Mendel (1866) et débattent : si un trait dominant est plus fréquent que son allèle récessif, va-t-il finir par supplanter ce dernier dans la population ?
En 1908, le statisticien anglais Udny Yule soutient que oui — que les traits dominants devraient s'imposer progressivement. Le biologiste Reginald Crundall Punnett (inventeur du carré de Punnett) doute de cette conclusion et consulte son ami mathématicien Godfrey Harold Hardy.
Hardy démontre en quelques lignes d'algèbre que les fréquences alléliques ne changent pas sous accouplement aléatoire — et publie une courte lettre dans Science en juillet 1908. La même année, le médecin allemand Wilhelm Weinberg aboutit indépendamment à la même conclusion. La loi porte leurs deux noms.
« Ce que Yule et d'autres ont pensé être un résultat important n'est en fait qu'une trivialité mathématique. » — Hardy, 1908
Mathématicien pur, connu pour ses travaux en théorie des nombres et en analyse. Il considérait ses travaux en biologie comme anecdotiques — pourtant la loi porte son nom. Auteur du célèbre A Mathematician's Apology (1940).
Médecin généraliste et généticien amateur passionné. Il publie ses résultats en allemand dans les Jahreshefte des Vereins für vaterländische Naturkunde — une revue locale peu lue, ce qui explique que sa contribution soit longtemps restée méconnue.
On considère un gène à deux allèles :
Il existe trois génotypes possibles :
| Génotype | AA | Aa | aa |
|---|---|---|---|
| Phénotype | Dominant | Dominant | Récessif |
| Fréquence à l'équilibre HW | $p^2$ | $2pq$ | $q^2$ |
Dans une population idéale (voir conditions §2.3), les fréquences génotypiques atteignent dès la première génération l'équilibre :
$$\boxed{f(AA) = p^2 \qquad f(Aa) = 2pq \qquad f(aa) = q^2}$$Et elles restent stables de génération en génération, avec $p^2 + 2pq + q^2 = (p+q)^2 = 1$.
Sous accouplement aléatoire, chaque parent transmet un allèle choisi au hasard parmi ses deux allèles. La probabilité de transmettre A vaut $p$, celle de transmettre a vaut $q$.
La probabilité qu'un enfant reçoive :
Ces fréquences génotypiques donnent bien des fréquences alléliques :
$f(A) = f(AA) + \tfrac{1}{2}f(Aa) = p^2 + pq = p(p+q) = p$ ✓
Les fréquences alléliques sont invariantes de génération en génération. $\blacksquare$
Chaque chemin donne la probabilité d'un génotype. Les deux chemins Aa et aA se combinent en $2pq$.
En pratique, ces conditions ne sont jamais toutes réunies — c'est précisément pour cela que la loi est utile : un écart aux fréquences HWE révèle qu'une de ces forces est à l'œuvre.
On observe dans une population la fréquence du phénotype récessif (génotype aa), qui est la seule fréquence génotypique directement lisible sur les phenotypes.
La phénylcétonurie (PKU) est une maladie métabolique récessive. En Europe, environ 1 naissance sur 10 000 est atteinte, soit $q^2 = 0{,}0001$.
On en déduit :
Ainsi environ 1 personne sur 50 est porteuse saine — sans le savoir.
La simulation part de fréquences génotypiques arbitraires (pas à l'équilibre) avec la fréquence allélique $p_0$ choisie, puis applique l'accouplement aléatoire sur plusieurs générations.
Simulation de la loi de Hardy-Weinberg et de la dérive génétique :
import random import matplotlib.pyplot as plt def generation_hw(p): """Retourne les fréquences génotypiques à l'équilibre HW.""" q = 1 - p return p**2, 2*p*q, q**2 # f(AA), f(Aa), f(aa) def derive_genetique(p0, N, G=50): """Simule la dérive génétique sur G générations, population de taille N.""" p = p0 historique = [p] for _ in range(G): # Chaque individu tire 2 allèles au hasard : A avec proba p, a avec proba 1-p alleles_A = sum(random.random() < p for _ in range(2 * N)) p = alleles_A / (2 * N) historique.append(p) if p == 0 or p == 1: break # fixation return historique # ── Équilibre Hardy-Weinberg ────────────────────────────────────── p0 = 0.3 generations = range(15) fAA, fAa, faa = [], [], [] # Partir d'une fréquence génotypique arbitraire (pas à l'équilibre) fAA_cur, fAa_cur, faa_cur = 0.05, 0.50, 0.45 p = fAA_cur + fAa_cur / 2 for _ in generations: fAA.append(fAA_cur); fAa.append(fAa_cur); faa.append(faa_cur) fAA_cur, fAa_cur, faa_cur = generation_hw(p) # HW atteint dès gen 1 fig, axes = plt.subplots(1, 2, figsize=(12, 4)) # Graphe 1 : convergence vers HW axes[0].stackplot(generations, fAA, fAa, faa, labels=['AA ($p^2$)', 'Aa ($2pq$)', 'aa ($q^2$)'], colors=['#1a6b5a', '#f0b429', '#c0392b'], alpha=0.85) axes[0].set_title('Équilibre Hardy-Weinberg (p₀ = 0.3)') axes[0].set_xlabel('Génération'); axes[0].set_ylabel('Fréquence génotypique') axes[0].legend(loc='upper right', fontsize=8) # Graphe 2 : dérive génétique (3 simulations) for col, N in zip(['#e74c3c', '#3498db', '#2ecc71'], [20, 100, 500]): hist = derive_genetique(0.5, N, G=80) axes[1].plot(hist, color=col, lw=1.2, label=ff'N = {N}') axes[1].axhline(0.5, color='black', ls='--', lw=1, alpha=0.4, label='HW théorique') axes[1].set_title('Dérive génétique selon la taille de la population') axes[1].set_xlabel('Génération'); axes[1].set_ylabel('Fréquence $p$ de A') axes[1].legend(fontsize=8) plt.tight_layout(); plt.show() print(f"Équilibre HW pour p = {p:.2f} : AA={p**2:.4f}, Aa={2*p*(1-p):.4f}, aa={(1-p)**2:.4f}")
Exécution pas à pas — calcul des fréquences HW à partir d'une population donnée :
L'intérêt de la loi HW est d'être un modèle de référence : si les fréquences observées s'en écartent, c'est le signe qu'une des 5 conditions est violée :