遗传算法(GA)的简单python实现

文章介绍了遗传算法的基本原理和流程,包括初始化、适应度函数、选择、交叉和变异操作。提供了一个简单的Python实现例子,其中适应度函数为f(x)=x^2,选择方式采用轮盘赌法,用于解决函数优化问题。通过交叉和变异操作,逐步优化种群,寻找最优解。
摘要由CSDN通过智能技术生成

由于课程即研究方向需要,简单实现一些关于智能优化的算法。

算法过程实现方式比较简单,没有用比较复杂的语句并且对代码进行了注释,比较适合小白。

遗传算法(Genetic Algorithm,GA)是一种基于生物进化思想的优化算法,它通过模拟生物进化过程中的遗传、交叉、变异和选择等基本操作来不断优化种群,从而实现对问题的求解。广泛应用于函数优化、组合优化、路径规划、机器学习等领域。遗传算法的基本思想是:将问题的解表示为染色体形式,通过基因重组、突变等操作来产生新的染色体,并以适应度函数来衡量每个染色体的适应性,然后根据适应度大小进行选择、交叉和变异等操作,最终得到更优的染色体,进而得到更优的解。遗传算法的基本流程如下:

  1. 初始化:随机生成初始种群,每个个体表示一个可能的解。

  1. 适应度函数:根据问题的特点,定义适应度函数,用于衡量每个个体的适应性。

  1. 选择:根据适应度函数的值,选择适应性较好的个体,作为下一代种群的基础。

  1. 交叉:对选出的个体进行交叉操作,产生新的个体。

  1. 变异:对新产生的个体进行变异操作,引入新的基因,增加种群多样性。

  1. 终止条件:当达到预定的终止条件时,停止算法,并返回最优解。遗传算法具有较好的全局搜索能力和高效的并行性,能够自适应地学习和演化规则,适用于复杂问题的求解。但也存在一些问题,如可能陷入局部最优解、需要大量的计算资源和时间等。因此,在使用遗传算法时,需要根据具体问题来选择适当的参数和操作,以获得更好的性能和效果。

由于只是简单实现,所以适应度函数f(x)=x^2.

选择是采用轮盘赌的方式

import math
import random

# 遗传算法的参数
M = 100  # 种群数量
T = 50  # 迭代次数
# 变异概率是个范围,因此用两个值表示
Pm1 = 0.001
Pm2 = 0.01
# 交叉概率
Pc1 = 0.4
Pc2 = 0.9
NUM_VARIABLES = 20  # 变量数量
MIN_VALUE = 0  # 变量最小值
MAX_VALUE = 1023  # 变量最大值
NUMBER_BINARY = math.ceil(math.log2(MAX_VALUE))  # 二进制位数,需要通过变量最大值来对2取对数然后通过ceil方法向上取整
SELECT_NUMBERS = 30  # 选择次数



# 生成随机个体
#这里生成个体采用三维数组的方式,总共有100个个体 分为了5组 每组20个个体,每个个体的第一个位置放的是他的值,后面10位放的是该值的二进制数
#因为这样在后面的交叉与变异后有助于更新他的值
def generate_individual():
    array = []
    for k in range(M // NUM_VARIABLES):
        col = []
        for i in range(NUM_VARIABLES):
            row = []
            row.append(random.randint(MIN_VALUE, MAX_VALUE))
            # 采用bin方法将得到的整数转化为二进制数,[2:]表示去掉前缀0b
            binary = bin(row[0])[2:]
            """
            将二进制数转化为10位固定长度的二进制数,
            其中,字符串格式化函数"{:0>8}"表示将字符串填充到8位长度,不足部分用0补齐,
            ">"表示右对齐,"0"表示用0填充。
            """
            fixed_binary = "{:0>10}".format(binary)
            for j in range(NUMBER_BINARY):  # 其实总共有11位 但前面已经将整数值添加到一个元素位置了
                row.append(int(fixed_binary[j]))
            col.append(row)
        array.append(col)
    print(array)
    return array


# 计算个体的适应度
def fitness(individual):
    return individual ** 2;


"""
交叉操作
还是需要从几组中选择一组,然后对该组中的个体进行操作,
操作完成之后需要更新种群,最终返回的是一个种群
"""
def crossover(population1):
    # 首先从种群中选择一组
    num = random.randint(0, M // NUM_VARIABLES - 1)
    print("选择种群组数为: ")
    print(num)
    population = population1[num]
    print(population)
    # 随机选择其中的两个个体进行交叉操作
    num1 = random.randint(0, NUM_VARIABLES - 1)
    num2 = random.randint(0, NUM_VARIABLES - 1)
    while num1 == num2:
        num2 = random.randint(0, NUM_VARIABLES - 1)
    parent1 = population[num1]
    parent2 = population[num2]
    print("选择个体1: ", parent1)
    print("选择个体2: ", parent2)
    # 随机生成一个在交叉概率范围内的数 然后在这个位置进行交叉
    cross = random.randint(int(Pc1 * NUMBER_BINARY), int(Pc2 * NUMBER_BINARY))
    print("交叉位置: ", cross)
    # 将两个个体的前cross个染色体进行交换
    for i in range(1, cross + 1):  # 因为个体存染色体是从第一个位置开始的,第0个位置是他的值
        temp = parent1[i]
        parent1[i] = parent2[i]
        parent2[i] = temp
    binary1 = ''
    binary2 = ''
    # 交换完成后要更新个体的值
    for j in range(1, len(parent1)):
        binary1 += str(parent1[j])
        binary2 += str(parent2[j])
    # 将二进制转化为十进制数并放入个体中的第0个位置
    parent1[0] = int(binary1, 2)
    parent2[0] = int(binary2, 2)
    print("交叉后的个体1: ", parent1)
    print("交叉后的个体2: ", parent2)
    # 最后更新种群
    population[num1] = parent1
    population[num2] = parent2
    population1[num] = population
    # 返回交叉后的种群
    return population1


# 变异操作
# 变异概率决定了要变异几次(即染色体变异的个数)
def mutate(population1):
    # 首先根据变异概率确定变异次数 因为总共有100个个体 每个个体有10染色体
    num = random.randint(M * NUMBER_BINARY * Pm1, M * NUMBER_BINARY * Pm2)
    while num > 0:
        # 随机选择种群中的一组中的一个个体的一个染色体
        num1 = random.randint(0, M // NUM_VARIABLES - 1)
        num2 = random.randint(0, NUM_VARIABLES - 1)
        individual = population1[num1][num2]
        num3 = random.randint(1, NUMBER_BINARY)
        print("被选中的个体为: ", individual)
        print("染色体变异位置: ", num3)
        # 将该染色体制反(即若为1 则置为0 反之)
        if (individual[num3] == 0):
            individual[num3] = 1
        else:
            individual[num3] = 0
        # 更新该个体的值
        binary1 = ''
        # 交换完成后要更新个体的值
        for j in range(1, len(individual)):
            binary1 += str(individual[j])
        individual[0] = int(binary1, 2)
        print("个体变异后的值: ", individual)
        # 更新种群
        population1[num1][num2] = individual
        # 循环次数-1
        num = num - 1
    return population1


# 选择操作
"""
选择操作是先算出每一个个体的适应度,然后根据适应度算出累积概率。
算出累积概率后,随机生成一个0-1之间的小数 判断其在哪个范围内。
选择次数是根据
"""
def selection(population1):
    # 随机选择种群数量中的一组  这里每一组为20个物种
    num = random.randint(0, M // NUM_VARIABLES - 1)
    print("选择种群组数为: ", num)
    population = population1[num]
    print(population)
    fitnesses = [fitness(individual[0]) for individual in population]
    print("每个个体的适应度为: ", fitnesses)
    min_fitness = min(fitnesses)
    max_fitness = max(fitnesses)
    print("最大适应度为: ", max_fitness)
    total_fitness = sum(fitnesses)
    cumulative_probability = []  # 累积概率
    cul = 0
    for i in range(len(fitnesses)):
        cul += fitnesses[i]
        cumulative_probability.append(cul / total_fitness)
    print(cumulative_probability)
    select = []  # 用于存放不同个体被选择的次数
    for b in range(NUM_VARIABLES):
        select.append(0)
    # 选择次数(这里采用轮盘赌选择方式)
    for s in range(SELECT_NUMBERS):
        probability = random.random()  # 随机生成一个概率
        # 判断这个概率在哪个之间 则该个体的选择次数加1
        for p in range(NUM_VARIABLES):
            if probability < cumulative_probability[p]:
                select[p] = select[p] + 1
                break
    print(select)
    # 表格头部
    print('物种适应度\t选择次数')
    # 表格内容
    for ani, sel in zip(fitnesses, select):
        print(f'{ani}\t\t{sel}')


# 主程序
population = generate_individual()
print("初始种群为: ", population)
print()
# 选择该种群数值最大的一个
max1 = 0
for i in range(M // NUM_VARIABLES):
    for j in range(NUM_VARIABLES):
        if (population[i][j][0] > max1):
            max1 = population[i][j][0]
print("该种群个体数值最大为: ", max1)

# 选择
selection(population)
for i in range(T):  # 迭代T次
    print("迭代次数: ", i)
    croPopulation = crossover(population)  # 交叉操作
    mutPopulation = mutate(croPopulation)  # 变异操作
    population = mutPopulation
    print()
# 选择该种群数值最大的一个
max = 0
for i in range(M // NUM_VARIABLES):
    for j in range(NUM_VARIABLES):
        if (population[i][j][0] > max):
            max = population[i][j][0]
print("该种群个体数值最大为: ", max)

结果展示:

总共迭代了50次中间迭代结果就不给出了,如果想要看,自己运行即可。

一般经过交叉变异之后,该种群都会变得比较好,这里好的定义就是 该种群中个体的适应度值,最初最大是1001,经过交叉变异之后1020.

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值