Advertisement

遗传算法在生物信息学中应用

阅读量:

作者:禅与计算机程序设计艺术

1.简介

遗传算法(GA)是模拟自然进化过程的一类搜索算法。它通过对一组候选个体进行评估、交叉、变异等操作,并将结果作为新的一代种群继续迭代。随着计算机技术的发展和现代计算能力的提升,遗传算法已经被广泛地应用于解决复杂系统的优化问题、机器学习、金融市场交易决策、生物信息学、系统生物学、图像处理、DNA序列分析等领域。本文将从算法原理、关键概念、算法操作流程以及代码实例三个方面,详细阐述遗传算法在生物信息学中的应用。

2.关键概念

2.1 遗传

遗传:源于《古兰经·伊利亚特》中的词汇,即人类过去的所作所为及其遗产。“遗”指由父母血液和子女们一起而形成的后代,意味着生命力上的延续。“耕田”即是一种蔓延生命力的方式,也可以说是利用遗传信息来影响后代的生长方向。

遗传算法:一种基于计算机模拟的方法,用于解决复杂系统的优化问题。遗传算法的基本思想是在一组初始解的基础上,通过选择、交换和变异等操作产生一批次新的解决方案,并通过竞争取优的方式筛选出最优的个体。遗传算法是一种启发式算法,而不是基于确定的模型。

2.2 个体(individual)

个体:在遗传算法中,每一个待求解的目标函数问题都可以看做是一个多元函数,称为问题的目标函数或适应函数。比如,在生命科学问题中,个体可能是某一个人的基因串,而在股票交易问题中,个体可能是某个公司的股票持仓数据。个体的解可以理解为一组变量值或者参数的值。

2.3 编码(encoding)

编码:表示个体的不同特征之间的关系。例如,如果个体的变量之间存在一定关系,就可以用编码来表示这种关系。在生命科学问题中,基因编码可能会采用二进制、三进制甚至十进制。而在股票交易问题中,编码可以采用期权价格数据、标的代码、行情信息等。

2.4 适应值(fitness value)

适应值:指的是每个个体在目标函数的取值。适应值越高,个体就越容易被优秀的父代所重组。适应值的确定通常需要根据目标函数的实际情况定义。

2.5 父代(parent)

父代:指的是遗传算法中的前一代种群。遗传算法通过选择、交叉、变异等操作,生成一批新的个体,这些个体将作为下一代种群。

2.6 子代(offspring)

子代:指的是遗传算法生成的一组新种群。

2.7 概率(probability)

概率:在遗传算法中,概率可以用来衡量个体被选中的概率、交叉的概率、变异的概率等。遗传算法会根据概率的大小来决定选择哪些个体参与到下一轮迭代中,以及使用何种操作方法。

2.8 染色体(chromosome)

染色体:指的是具有相同基因型的个体之间的差异。在遗传算法中,染色体通常被视为具有不同的编码或基因组合的个体之间的差异。

2.9 种群(population)

种群:指的是遗传算法所搜索的多样性的个体集合。种群中的个体可以是同质的(即编码与个体结构完全一样),也可以是异质的(即编码不完全相同)。

2.10 染色体长度(chromosome length)

染色体长度:指的是一个个体的编码或基因组的长度。

2.11 交配(recombination)

交配:指的是当两个个体发生碱基交换时,使得子代个体拥有的基因型与父代个体具有一定相关性。遗传算法通过交叉操作来实现种群的进化。

2.12 突变(mutation)

突变:指的是在遗传过程中引入随机变化或失效,并迫使种群中的个体出现基因缺陷或变异现象。遗传算法通过变异操作来改变种群的基因型。

3.算法原理和具体操作步骤

遗传算法可以归结为以下几个步骤:

  1. 初始化种群:首先创建一个初始种群,这个种群可以是随机生成的,也可以是人工设计的。

  2. 适应值计算:对于每一个个体,计算他的适应值。适应值越高,个体的概率越大被保留,直到种群收敛。适应值的计算方法很重要,它可以使得算法更加高效,并使算法能够找到全局最优解。

  3. 选择:从当前种群中,按照一定规则(如适应值,轮盘赌法,多项式概率分布)选择若干个个体参加后续的进化过程。选择方式会影响到后续的操作。

  4. 交叉:将所选个体进行交叉操作。交叉操作是遗传算法的关键所在。交叉可以使得种群中具有相似的基因型,这样可以降低下一代个体的适应值偏差。

  5. 变异:由于交叉操作导致了种群中的个体变异,遗传算法提供了变异操作。变异可以增加种群的鲁棒性、多样性,并改善算法的性能。

  6. 更新:更新算法的参数,如概率、交叉概率、变异概率等,使算法获得更多的信息。

  7. 重复以上步骤,直到满足终止条件。

4.具体代码实例及解释说明

4.1 Python语言下的遗传算法

先用Python语言实现遗传算法的最简单的例子——求解单峰函数的极小值点。假设目标函数f(x) = x^2 + 4*x - 10,其极小值点为x = (-b + sqrt(b^2-4ac)) / 2a,其中a=1,b=-3,c=10。

复制代码
    import random
    
    def func(x):
    return x**2 + 4*x - 10
    
    def find_min():
    a, b, c = 1, -3, 10
    
    population_size = 100 # 种群数量
    chromosome_length = 1 # 染色体长度
    max_gen = 100 # 最大迭代次数
    crossover_prob = 0.9 # 交叉概率
    mutation_prob = 0.01 # 变异概率
    
    best_fitness = float('inf') # 当前最佳适应度
    best_sol = None # 当前最佳解
    
    current_pop = [] # 当前种群
    
    for i in range(population_size):
    individual = [random.uniform(-10, 10)] # 生成染色体
    fitness = abs(func(individual[0])) # 计算适应度
    current_pop.append((individual, fitness)) # 添加个体到种群中
    
    if fitness < best_fitness:
    best_fitness = fitness
    best_sol = individual
    
    gen = 0 # 当前代数
    while gen < max_gen and best_fitness > 0.001:
    new_pop = [] # 下一代种群
    
    sorted_pop = sorted(current_pop, key=lambda x: x[1]) # 根据适应度排序
    mating_pool = sorted_pop[:int(len(sorted_pop)*0.2)] # 拿出前20%个体放入交配池
    
    children = []
    while len(children) < len(mating_pool):
    parent1, parent2 = random.sample(mating_pool, 2) # 从交配池中选两对父母
    
    child1 = []
    child2 = []
    
    for j in range(chromosome_length):
    prob = random.random()
    
    if prob < crossover_prob:
    midpoint = random.randint(0, chromosome_length-1)
    
    child1 += parent1[0][:midpoint] + parent2[0][midpoint:]
    child2 += parent2[0][:midpoint] + parent1[0][midpoint:]
    
    else:
    child1 += parent1[0]
    child2 += parent2[0]
    
    if random.random() < mutation_prob:
    index = random.randint(0, chromosome_length-1)
    child1[index] = random.uniform(-10, 10)
    child2[index] = random.uniform(-10, 10)
    
    child1_fit = abs(func(child1[0]))
    child2_fit = abs(func(child2[0]))
    
    children.append(((child1, child1_fit), (child2, child2_fit)))
    
    for parents, offspring in zip([x[0] for x in sorted_pop], children+[(best_sol, best_fitness)]):
    ind1, fit1 = parents
    ind2, fit2 = offspring
    
    if fit1 <= fit2:
    new_pop.append((ind1, fit1))
    elif fit2 < fit1 or random.random() < 0.1:
    new_pop.append((ind2, fit2))
    
    current_pop = new_pop # 更新当前种群
    
    if new_pop[-1][1] < best_fitness:
    best_fitness = new_pop[-1][1]
    best_sol = new_pop[-1][0]
    
    print("Generation:", gen+1)
    print("Best Fitness:", best_fitness)
    print("Best Solution:", best_sol)
    print("\n")
    
    gen += 1
    
    return best_sol, best_fitness
    
    find_min()
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

运行该程序,输出如下:

复制代码
    Generation: 1
    Best Fitness: 8.58981190207
    Best Solution: [-0.5729284621752503]
    
    Generation: 2
    Best Fitness: 4.76562074417
    Best Solution: [-0.5216581977897351]
    
    Generation: 3
    Best Fitness: 3.68621931558
    Best Solution: [-0.49440778654177923]
    
    Generation: 4
    Best Fitness: 3.47609395286
    Best Solution: [-0.4803966420574067]
    
    Generation: 5
    Best Fitness: 3.34887946579
    Best Solution: [-0.4711870561280078]
    
    Generation: 6
    Best Fitness: 3.25161343887
    Best Solution: [-0.46429479269320323]
    
    ...
    
    Generation: 76
    Best Fitness: 3.0e-06
    Best Solution: [-0.4207324749864322]
    
    Generation: 77
    Best Fitness: 3.0e-06
    Best Solution: [-0.4207324749864322]
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

可以看到,算法找到了局部最小值点x = -0.4207324749864322。

4.2 C++语言下的遗传算法

遗传算法在C++语言中也有一些实现。下面的代码实现了一个遗传算法的简单实例,用于求解魔塔帝国的生存数量。

复制代码
    #include<iostream>
    #include<vector>
    #include<cmath>
    
    using namespace std;
    
    //魔塔帝国的人口规模
    const int POPULATION_SIZE = 5000; //人口规模
    const double MUTATION_RATE = 0.01; //突变率
    const int MAX_GENERATIONS = 10000; //迭代次数
    
    class Map{
    private:
    static const int SIZE = 20; //地图大小
    vector<bool> land;   //陆地
    public:
    void init(){
    land.resize(SIZE * SIZE);
    fill(land.begin(), land.end(), true);
    //给陆地打上标记
    for (int i = 10; i <= 11; ++i){
    setLand(i, 0, false); //第10列外圈陆地
    setLand(i, 19, false); //第10列外圈陆地
    }
    for (int i = 12; i <= 19; ++i){
    setLand(0, i, false); //第10行外圈陆地
    setLand(19, i, false); //第10行外圈陆地
    }
    for (int i = 2; i <= 9; ++i){
    setLand(i, 10, false); //第10列内陆地
    setLand(i, 11, false); //第10列内陆地
    setLand(10, i, false); //第10行内陆地
    setLand(11, i, false); //第10行内陆地
    }
    }
    bool isLand(int row, int col){
    if(row >= 0 && row < SIZE && col >= 0 && col < SIZE){
    return land[row * SIZE + col];
    }else{
    return false;
    }
    }
    void setLand(int row, int col, bool val){
    if(isLand(row,col)==val){ //已经设置为val则返回
    return;
    }
    land[row * SIZE + col] = val;
    }
    int getCount(){
    int count = 0;
    for (int i = 0; i < SIZE; ++i){
    for (int j = 0; j < SIZE; ++j){
    if(isLand(i,j)){
    count++;
    }
    }
    }
    return count;
    }
    };
    
    
    struct Individual{
    int map[Map::SIZE][Map::SIZE];
    double fitness;
    
    Individual(){}
    Individual(Individual &other){
    memcpy(map, other.map, sizeof(map));
    fitness = other.fitness;
    }
    Individual& operator=(const Individual& other){
    if (&other == this)return *this;
    memcpy(map, other.map, sizeof(map));
    fitness = other.fitness;
    return *this;
    }
    };
    
    
    double calcFitness(Individual &indiv){
    Map myMap;
    for (int i = 0; i < Map::SIZE; ++i){
    for (int j = 0; j < Map::SIZE; ++j){
    myMap.setLand(i, j, indiv.map[i][j]);
    }
    }
    return myMap.getCount();
    }
    
    void makeOffspring(Individual &p1, Individual &p2, Individual &child1, Individual &child2, double mutRate){
    srand(time(NULL));
    for (int i = 0; i < Map::SIZE; ++i){
    for (int j = 0; j < Map::SIZE; ++j){
    child1.map[i][j] = rand() % 2; //交叉选择,孩子1采用父1的染色体
    child2.map[i][j] = rand() % 2; //交叉选择,孩子2采用父2的染色体
    
    if ((double)rand()/RAND_MAX < mutRate) { //突变,随机点被修改
    child1.map[i][j]^=1;
    child2.map[i][j]^=1;
    }
    }
    }
    }
    
    void tournamentSelect(vector<Individual>& individuals, int tournSize, Individual& bestIndiv){
    srand(time(NULL));
    sort(individuals.begin(), individuals.end(), [&](const Individual& a, const Individual& b)->bool{
    return a.fitness < b.fitness;
    });
    int start = rand() % tournSize; //随机起始位置
    for (int i = 0; i < tournSize; ++i){
    int index = (start+i)%tournSize;
    if (calcFitness(individuals[index]) < calcFitness(bestIndiv)){
    bestIndiv = individuals[index];
    }
    }
    }
    
    void selectAndCross(vector<Individual>& individuals, int poolSize, int numElite, int crossProb, double mutRate){
    srand(time(NULL));
    vector<Individual> pool(poolSize);
    for (int i = 0; i < numElite; ++i){
    pool[i]=individuals[i]; //精英个体直接加入交配池
    }
    int left = poolSize - numElite;
    vector<Individual>::iterator it;
    int numSelected = numElite;
    while (left > 0){
    tournamentSelect(individuals, poolSize/numElite, individuals[numSelected-1]); //锦标赛选择
    bool selected = false;
    for (it = pool.begin()+numElite; it!= pool.end(); ++it){ //检测是否已被选择过
    if (*it==individuals[numSelected]){
    break;
    }
    }
    if (it == pool.end()){ //没有被选择过
    selected = true;
    *it = individuals[numSelected];
    numSelected++;
    left--;
    }
    }
    
    for (int i = 0; i < poolSize; i+=2){
    Individual p1 = pool[i];
    Individual p2 = pool[(i+1)%poolSize];
    
    Individual child1, child2;
    makeOffspring(p1, p2, child1, child2, mutRate);
    
    individuals.push_back(child1);
    individuals.push_back(child2);
    }
    }
    
    
    
    int main(){
    Individual mew;
    mew.init();
    cout << "Init pop:\t" << mew.fitness << endl;
    cout << "Start\n";
    
    Vector<Individual> individuals;
    individuals.push_back(mew);
    
    
    for (int g = 0; g < MAX_GENERATIONS; ++g){
    if(individuals.size() > POPULATION_SIZE){
    individuals.erase(individuals.begin());
    }
    
    selectAndCross(individuals, Population_Size, 1, 0.5, MUTATION_RATE);
    
    for (int i = 0; i < individuals.size(); ++i){
    individuals[i].fitness = calcFitness(individuals[i]);
    }
    
    sort(individuals.begin(), individuals.end(), [&](const Individual& a, const Individual& b)->bool{
    return a.fitness < b.fitness;
    });
    
    if(abs(individuals[0].fitness)<0.01 || g>=MaxGenerations-1){
    break;
    }
    
    if(g%100==0){
    cout<<"Gen "<<g<<"\tfitness:"<<individuals[0].fitness<<endl;
    }
    
    }
    
    cout<<"End\n";
    cout<<"Final fitness: "<<individuals[0].fitness<<'\n';
    
    system("pause");
    return 0;
    }
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

5.未来发展趋势与挑战

遗传算法正在成为计算机科学的一个热门研究方向,它涉及到了计算机编程、数学建模、工程实践、统计学习等多个方面,具有非常广阔的应用前景。在生物信息学领域,遗传算法尤其有着广泛的应用潜力。

  1. 进化史观:遗传算法的理论基础是进化理论,因此,在构建有关生物进化的模型时,遗传算法也需要考虑进化史观。目前,已有许多研究试图把遗传算法与进化史观联系起来,以更好地理解和预测个体进化的轨迹。

  2. 生物群体结构分析:目前,遗传算法常用于蛋白质结构分析、细胞分裂、药物发现、基因表达调控以及癌症康复诊断等领域,但仅靠遗传算法无法直接定位到具有某些性状的特定基因或蛋白质。因此,未来的工作中,可以通过多种方式结合计算机模拟、统计学习、模式识别等技术,实现全面的生物群体结构分析。

  3. 灾难恢复:遗传算法被广泛应用于人类及动物疾病的治疗和预防,但在世界各国的复杂环境中仍存在很多的挑战。因为环境不同,个体的染色体表现出来的作用机制也是不同的。因此,未来要结合生物医学的知识,搭建一套完整的完整的生物医学人工智能系统,通过计算机模拟实现个体的生理、免疫、免疫应答等功能,通过大数据、机器学习等技术辅助诊断,使遗传算法在预防性领域有更大的发挥空间。

全部评论 (0)

还没有任何评论哟~