知识导图:感觉写的好的话,求收藏,没动力了快,一篇写下来累死累活的。
全文围绕其简单题目:
遗传算法(概念)
可以把遗传算法类比成一个游戏,我们需要通过这个游戏来找到最佳的解决方案。
- 首先,我们需要创建一些角色(也就是种群),每个角色有自己的装备和技能(染色体),但是我们并不知道哪个角色更加强大。
- 然后,我们让这些角色相互竞争,通过升级、打怪等方式来获得经验值(适应度值)。经验值越高的角色,就拥有了更多胜利的可能性。
- 接着,我们会将经验值高的角色进行复制,将装备/技能进行升级,继承属性(对应其交叉操作),而一些随机变异的角色也会加入其中。这些新的角色代表了我们在寻找答案的过程中的探索。如果它们的表现好于之前的角色,那么我们就可以用它们来代替原来的角色。
- 最后,通过这样的迭代过程,我们会逐渐找到最强大的角色,也就是最优解。
- 总之,遗传算法通过不断地试错,从而找到最优解决方案,就像在玩游戏一样。
具体来说,遗传算法的流程包括以下几个步骤:
- 初始化种群:通过随机方式生成一组初始解,称为种群。
- 适应度函数:根据问题要求,设计一个适应度函数,用于评价每个个体的好坏程度。
- 选择操作:按照适应度函数的评价结果,从当前种群中选择一些优秀的个体作为父代,并使用复制、交叉等方法产生下一代种群。
- 变异操作:在新产生的个体中进行随机变异的操作,增加搜索的多样性。
- 终止条件:根据预设的停止条件(如迭代次数、达到最优解等)决定算法何时结束。
遗传算法通过不断地试错,在种群中选择、交叉和变异来生成新的个体,并计算它们的适应度值。然后,根据设定的适应度函数来选择出适应度值高的个体作为下一代的父母,再进行交叉和变异操作,生成新的个体。通过这样的迭代过程,逐渐找到最优解决方案
步骤:
1.初始化种群
初始化种群是指在遗传算法中,初始阶段按照其规定的编码方式随机生成一组个体,并将其作为遗传算法的起点。
这些个体构成了一个种群,每个个体都代表了问题的一个可能解。通过对这些个体进行交叉、变异等操作,不断迭代,从而逐步逼近问题的最优解。因此,初始化种群的质量和数量对于遗传算法的性能有很大影响。
基础篇,理解并学会使用以下三种编码方式方法:
- 二进制
整数(没学,有机会的话,放到进阶篇写)浮点数(没学,有机会的话,放到进阶篇写)
1.1二进制编码与解码
顾名思义,就是将10进制数编码成二进制数
以下是我总结的常用方式和其代码:
假设需要解决一个最小化函数f(x)(适应函数f),其中变量x是取值范围出现以下情况:
1. 当x是取值范围为[a,b]之间的实数。
:c⑩是随机生成的一个二进制串的10进制值
例如:10101的c⑩为21,
:n就是我们选取的二进制位数
例如:例子来源
例如:假设需要解决一个最小化函数f(x),其中变量x是取值范围为[0,10]之间的实数。可以将c表示为一个长度为n的二进制串。例如,当n=5时,可将二进制串c:10101带入公式
下面是最初题目的一些示例代码(主要工作就是初始化种群*100 二进制串---->c⑩)
代码:
import math import random # 求n(已知精度p,x的取值范围[a,b]) def calculate_n(p, a, b): power = math.log2((b - a) * 10 ** p) n = math.ceil(power) return n # 随机生成n位二进制数 def generate_binary_number(n): binary = "" for i in range(n): bit = random.randint(0, 1) binary += str(bit) return binary # 初始化种群(二进制版) def initialize_population(population_size, n): population = [] for i in range(population_size): individual = generate_binary_number(n) population.append(list(map(int,individual))) return population # 二进制编码 n位二进制的选择 n = calculate_n(1, -5, 5) print("n:", n) # 初始化种群 population_2 = initialize_population(100, n) print("初始化种群", population_2)
输出:
一般遗传题目中的变量是多维的(或者说多个变量),那么我们采用的一般都是将其转化为1维的二进制串,当然,这不属于我的基础篇内容,可以了解下以下内容:
2.选择操作
根据第一步初始化的种群,对其每个个体进行评价,选出适应度最高的个体作为下一代的父代。
所谓个体评价可以被视为对该个体在特定问题上表现优劣的度量。将个体带入适应度函数得到的适应度值作为判别依据。适应度函数是用来衡量每个个体相对于解决问题的能力或者质量的函数。评价指标通常越高,表示个体在当前环境下的适应度越好。通过比较不同个体的适应度,可以选出适应度最高的个体作为下一代的父代。
选择操作是一种基于适应度的算法,通过使用某些技术从当前群体中选出适应性较高的个体作为下一代的父代。这种方法可以反复迭代,以提高整个群体的适应度水平。
2.1 拿到个体适应度
函数代码:
# 得到相应区间的x值 def binary_to_x(binary_list, a, b, n): x_list = [] range_value = b - a for binary in binary_list: decimal = int("".join(map(str, binary)), 2) ratio = decimal / (2 ** n - 1) x = ratio * range_value + a x_list.append(x) return x_list # 求x x = binary_to_x(population_2, -5, 5, n) x = [round(num, 1) for num in x] print("x", x)
输出:
def fitness(x): return round(x ** 2 - 3 * x + 4, 1) # 求适应度 fitness_values = [fitness(x) for x in x] print("适应度", fitness_values)
输出:
2.2 轮盘赌选择
轮盘赌选择是一种常用的遗传算法选择方法,也被称为比例选择。
轮盘赌选择法(roulette wheel selection)是最简单也是最常用的选择方法,在该方法中,各个个体的选择概率和其适应度值成比例,适应度越大,选中概率也越大。
但实际在进行轮盘赌选择时个体的选择往往不是依据个体的选择概率,而是根据“累积概率”来进行选择。
解析:知乎轮盘赌选择
上式中的累积概率表示每个个体之前所有个体的选择概率之和,它相当于在转盘上的“跨度”,“跨度”越大越容易选到,就相当于概率论中的概率分布函数F(x)。轮盘赌选择法的过程如下:
(1)计算每个个体的被选中概率p(xi)
(2)计算每个部分的累积概率q(xi)
(3)随机生成一个数组m,数组中的元素取值范围在0和1之间,并将其按从小到大的方式进行排序。若累积概率q(xi)大于数组中的元素m[i],则个体x(i)被选中,若小于m[i],则比较下一个个体x(i+1)直至选出一个个体为止。
(4)若需要转中N个个体,则将步骤(3)重复N次即可.