基于 Python 的对果蝇基因自由组合的模拟
使用 Python 模拟果蝇减数分裂产生配子和受精作用的过程,进而模拟性状分离比,测试基因自由组合、基因连锁和伴性遗传现象。
程序设计
染色体 Chromosome
染色体中用列表记录着该染色体携带的基因。
# 染色体
@dataclass()
class Chromosome:
_genes: list[Gene] # 基因列表
@property
def genes(self) -> list[Gene]:
return self._genes
染色体组 Genome
两个染色体组可以表示一个果蝇个体,一个染色体组可以表示一个成熟配子。
我使用字典来表示一个染色体组:由染色体编号到染色体的映射构成。
具体来说,果蝇的一个染色体组由四条染色体构成:I、II、III、IV,其中 I 是性染色体,II、III、IV 是常染色体。
# 染色体编号
ChromosomeType = Literal['I', 'II', 'III', 'IV']
# 染色体组
Genome = dict[ChromosomeType, Chromosome]
果蝇个体 DM
一个果蝇个体由两个染色体组构成,分别来自父本和母本。
果蝇个体可以通过减数分裂产生一些配子。
# 果蝇个体 Drosophila melanogaster
@dataclass()
class DM:
_ch_from_mp: Genome # 继承自父本(male parent)的染色体
_ch_from_fp: Genome # 继承自母本(female parent)的染色体
# 通过染色体和基因创造一只果蝇
@classmethod
def create(cls, genome_from_mp: dict[ChromosomeType, str],
genome_from_fp: dict[ChromosomeType, str]) -> 'DM': ...
# 果蝇的性别
@property
def sex(self) -> Sex: ...
# 减数分裂产生一个配子列表
def meiosis(self) -> list[Genome]: ...
减数分裂 meiosis
模拟减数分裂的过程,依次决定每条染色体进入哪一个配子,最后产生 300 到 500 个配子。
不考虑四分体时期的同源染色体交叉互换,不考虑突变。
def meiosis(self) -> list[Genome]:
ret: list[Genome] = []
quantity = random.randint(300, 500) # 减数分裂的次数
for _ in range(quantity):
# 非同源染色体自由组合
# 产生的两种不同的配子
a: Genome = {}
b: Genome = {}
ct: ChromosomeType
for ct in ('I', 'II', 'III', 'IV'):
# 同源染色体分离
# 随机决定这一条染色体进入哪个配子
if random.choice([True, False]):
a[ct] = self._ch_from_mp[ct]
b[ct] = self._ch_from_fp[ct]
else:
b[ct] = self._ch_from_mp[ct]
a[ct] = self._ch_from_fp[ct]
ret.append(a)
ret.append(b)
return ret
杂交过程 hybrid
对一雌一雄果蝇个体进行杂交,产生 300 到 500 个子代果蝇个体。
雌雄果蝇分别产生配子,再随机抽取雌雄配子进行受精,得到子代果蝇个体。
不考虑突变。
# @brief 杂交
# @param mp Male parent.
# @param fp Female parent.
# @return Filial generation.
def hybrid(mp: DM, fp: DM) -> list[DM]:
assert mp.sex == 'M'
assert fp.sex == 'F'
mg = mp.meiosis() # 雄配子
fg = fp.meiosis() # 雌配子
quantity = random.randint(300, 500) # 子代数量
ret: list[DM] = []
for _ in range(quantity):
a = random.choice(mg)
b = random.choice(fg)
ret.append(DM(a, b))
return ret
数据模拟
杂合子自交性状分离比
亲本:Aa × Aa
| 子代 | AA | Aa | aa | 总计 |
|---|---|---|---|---|
| 预期比例 | 1.0 | 2.0 | 1.0 | \ |
| 实际数量 | 15984 | 32090 | 15973 | 64047 |
| 实际比例 | 1.0007 | 2.0090 | 1.0 | \ |
结论:在误差允许范围内,符合预期的结果。
基因自由组合定律模拟
亲本:AAbb × aaBB
| F1 | AaBbXY | AaBbXX | 总计 |
|---|---|---|---|
| 预期比例 | 1.0 | 1.0 | \ |
| 实际数量 | 243 | 252 | 495 |
| 实际比例 | 0.9643 | 1.0 | \ |
| F2 | A_B_ | A_bb | aaB_ | aabb | 总计 |
|---|---|---|---|---|---|
| 预期比例 | 9.0 | 3.0 | 3.0 | 1.0 | \ |
| 实际数量 | 54826 | 18183 | 18311 | 6150 | 97470 |
| 实际比例 | 8.9148 | 2.9566 | 2.9774 | 1.0 | \ |
结论:在误差允许范围内,符合预期的结果。
伴 X 染色体隐性遗传病雌雄发病率对比测试
亲本:X(B)X(b) × X(B)Y
| F009 | 总数 | 隐性发病数 | 发病率 |
|---|---|---|---|
| ♂ | 83067 | 27951 | 33.649 % |
| ♀ | 82991 | 9593 | 11.559 % |
| 全体 | 166058 | 37544 | 22.609 % |
| F101 | 总数 | 隐性发病数 | 发病率 |
|---|---|---|---|
| ♂ | 97827 | 25513 | 26.080 % |
| ♀ | 98158 | 7287 | 7.424 % |
| 全体 | 195985 | 32800 | 16.736 % |
| F149 | 总数 | 隐性发病数 | 发病率 |
|---|---|---|---|
| ♂ | 65240 | 18441 | 28.266 % |
| ♀ | 65331 | 4084 | 6.251 % |
| 全体 | 130571 | 22525 | 17.251 % |
结论:雄性发病率远高于雌性发病率,符合预期;随繁殖代数增加,发病率逐渐趋于稳定。
附 完整代码
# coding=utf-8
import random
from dataclasses import dataclass
from typing import Literal
# 性别
Sex = Literal['M', 'F']
# 基因
Gene = Literal['X', 'Y', 'A', 'a', 'B', 'b', 'D', 'd', 'E', 'e', 'W', 'w']
# 染色体编号
ChromosomeType = Literal['I', 'II', 'III', 'IV']
# 染色体
@dataclass()
class Chromosome:
_genes: list[Gene] # 基因列表
@property
def genes(self) -> list[Gene]:
return self._genes
# 染色体组
Genome = dict[ChromosomeType, Chromosome]
# 果蝇个体 Drosophila melanogaster
@dataclass()
class DM:
_ch_from_mp: Genome # 继承自父本(male parent)的染色体
_ch_from_fp: Genome # 继承自母本(female parent)的染色体
@classmethod
def create(cls, genome_from_mp: dict[ChromosomeType, str],
genome_from_fp: dict[ChromosomeType, str]) -> 'DM':
assert 'X' == genome_from_fp['I'][0]
assert genome_from_mp['I'][0] in 'XY'
ct: ChromosomeType
mg: Genome = {}
for ct, genes in genome_from_mp.items():
mg[ct] = Chromosome(list(genes))
fg: Genome = {}
for ct, genes in genome_from_fp.items():
fg[ct] = Chromosome(list(genes))
return cls(mg, fg)
@property
def sex(self) -> Sex:
if 'X' in self._ch_from_mp['I'].genes:
return 'F' # XX -> female
return 'M' # XY -> male
def meiosis(self) -> list[Genome]:
ret: list[Genome] = []
quantity = random.randint(300, 500) # 减数分裂的次数
for _ in range(quantity):
# 非同源染色体自由组合
# 产生的两种不同的配子
a: Genome = {}
b: Genome = {}
ct: ChromosomeType
for ct in ('I', 'II', 'III', 'IV'):
# 同源染色体分离
# 随机决定这一条染色体进入哪个配子
if random.choice([True, False]):
a[ct] = self._ch_from_mp[ct]
b[ct] = self._ch_from_fp[ct]
else:
b[ct] = self._ch_from_mp[ct]
a[ct] = self._ch_from_fp[ct]
ret.append(a)
ret.append(b)
return ret
def __str__(self) -> str:
ret: str = ''
ct: ChromosomeType
# 处理常染色体
for ct in ('II', 'III', 'IV'):
mc: Chromosome = self._ch_from_mp[ct]
fc: Chromosome = self._ch_from_fp[ct]
for mg, fg in zip(mc.genes, fc.genes):
if mg.islower():
ret += fg + mg
else:
ret += mg + fg
# 对性染色体特殊处理
ct = 'I'
fc: Chromosome = self._ch_from_fp[ct]
for fg in fc.genes:
ret += fg
mc: Chromosome = self._ch_from_mp[ct]
for mg in mc.genes:
ret += mg
return ret
# @brief 杂交
# @param mp Male parent.
# @param fp Female parent.
# @return Filial generation.
def hybrid(mp: DM, fp: DM) -> list[DM]:
assert mp.sex == 'M'
assert fp.sex == 'F'
mg = mp.meiosis() # 雄配子
fg = fp.meiosis() # 雌配子
quantity = random.randint(300, 500) # 子代数量
ret: list[DM] = []
for _ in range(quantity):
a = random.choice(mg)
b = random.choice(fg)
ret.append(DM(a, b))
return ret
# @brief 繁育
# @param mp Male parent.
# @param fp Female parent.
# @return mf Male filial generation.
# @return ff Female filial generation.
def breed(mp: list[DM], fp: list[DM]) -> tuple[list[DM], list[DM]]:
mf: list[DM] = []
ff: list[DM] = []
quantity = random.randint(300, 500)
quantity = min(quantity, len(mp), len(fp))
mp = random.sample(mp, quantity)
fp = random.sample(fp, quantity)
for m, f in zip(mp, fp):
fg = hybrid(m, f)
for dm in fg:
if dm.sex == 'M':
mf.append(dm)
else:
ff.append(dm)
# mf = random.sample(mf, 100)
# ff = random.sample(ff, 100)
return mf, ff
# @brief 统计
# @param sample 样本
# @param genes 要求具有的所有基因
# @return 样本中符合要求的个体数
def count(sample: list[DM], genes: str) -> int:
genes = list(genes)
cnt: int = 0
for dm in sample:
dm_genes = list(dm.__str__())
for g in genes:
if g in dm_genes:
dm_genes.remove(g)
else:
break
else:
cnt += 1
return cnt
if __name__ == '__main__':
mp: DM = DM.create(
{
'I': 'Y',
'II': 'A',
'III': 'b',
'IV': '',
}, {
'I': 'X',
'II': 'A',
'III': 'b',
'IV': '',
}
)
fp: DM = DM.create(
{
'I': 'X',
'II': 'a',
'III': 'B',
'IV': '',
}, {
'I': 'X',
'II': 'a',
'III': 'B',
'IV': '',
}
)
print(mp, fp)
print()
f1 = hybrid(mp, fp)
mf: list[DM] = []
ff: list[DM] = []
for dm in f1:
if dm.sex == 'M':
mf.append(dm)
else:
ff.append(dm)
print(mf[0], ff[0])
print()
mf, ff = breed(mf, ff)
print(mf[0], ff[0])
print()
f2 = mf + ff
a = count(f2, 'AB')
b = count(f2, 'Abb')
c = count(f2, 'aaB')
d = count(f2, 'aabb')
print(len(f2), '\n', a, b, c, d, '\n', a / d, b / d, c / d, d / d)
a = count(f2, 'A')
b = count(f2, 'aa')
print(a, b, '\n', a/b, b/b)
# mf, ff = breed(mf, ff)
# print(mf[0], ff[0])
# print()
#
# mf, ff = breed(mf, ff)
# print(mf[0], ff[0])
# print()
本文来自博客园,作者:Gyan083,转载请注明原文链接:https://www.cnblogs.com/gyan083/p/16603178.html

浙公网安备 33010602011771号