基于 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()

posted @ 2022-08-19 19:48  Gyan083  阅读(461)  评论(2)    收藏  举报