Exercise 1 solution from fractions import Fraction pops = { "north": {"AA": 49, "Aa": 42, "aa": 9}, "south": {"AA": 20, "Aa": 60, "aa": 20}, "east": {"AA": 5, "Aa": 30, "aa": 65}, } for name, obs in pops.items(): n = sum(obs.values()) p = Fraction(2 * obs["AA"] + obs["Aa"], 2 * n) q = 1 - p exp = {"AA": p * p * n, "Aa": 2 * p * q * n, "aa": q * q * n} chi = sum((obs[g] - float(exp[g])) ** 2 / float(exp[g]) for g in obs) print(name, "p =", p, "q =", q) print(" expected", {g: float(v) for g, v in exp.items()}) print(" chi-square", round(chi, 2), "fits" if chi < 3.84 else "does not fit") Output: north p = 7/10 q = 3/10 expected {'AA': 49.0, 'Aa': 42.0, 'aa': 9.0} chi-square 0.0 fits south p = 1/2 q = 1/2 expected {'AA': 25.0, 'Aa': 50.0, 'aa': 25.0} chi-square 4.0 does not fit east p = 1/5 q = 4/5 expected {'AA': 4.0, 'Aa': 32.0, 'aa': 64.0} chi-square 0.39 fits Reading it: the first population matches the baseline exactly. The second has too many heterozygotes (60 against 25 + 50 + 25 expected), giving 4.0, just above the 3.84 cut-off. The third is close to the baseline even though the allele a is common (4/5), because the test compares genotype counts to what the allele frequencies predict, not allele frequencies to each other.