遗传算法 - 无序变长染色体 - 交叉策略?

时间:2018-02-13 19:04:23

标签: python algorithm genetic-algorithm genetic-programming

我正在研究遗传算法。染色体没有排序 - 这意味着它们在成员中出现的顺序不会影响成员的得分。染色体的数量也不固定。一个成员可能有1个染色体,另一个可能有100多个。

我在Python工作,染色体存储在列表中。以下是结构的简化示例:

member = [{"key1":"value","key2":"value"},{"key1":"value","key2":"value"},{"key1":"value","key2":"value"}]

两个示例成员(简化)可能是:

member1 = [{"a":1.5,"b":2.334563},{"a":769.0003413,"b":0.00023}]
member2 = [{"a":7,"b":432.993246927},{"a":99,"b":532.234},{"a":21,"b":712.2},{"a":432,"b":999.9999},{"a":932,"b":12}]

在应用程序中重复出现乱序的染色体:

member3 = [{"a":1,"b":1},{"a":2,"b":2},{"a":2,"b":2},{"a":1,"b":1}]

成员

成员中的每个染色体都是一个数学函数,它将Unix epoc时间戳作为输入,并输出一个值。这让我可以获得价值'任何时候使用该成员的功能。染色体中的键始终相同 - 但在初始播种期间随机生成的值范围为0到100,最多100个小数位。

评分系统

我根据SQL数据库中的实时序列数据对函数进行评分。时间序列数据每隔1到3秒不断更新一次新值。当我对这些数据进行选择时,我选择epoc值大于当前epoc的位置 - 5秒并按降序排序,并将输出限制为1行。我记下了返回的实际epoc值,这是我评分的分数之一。

我取所有点(epoc:值对)并使用它们进行评分,为成员函数提供epoc,获取成员的值,然后从实际值中减去该值 - 并取绝对值价值。

看起来有点像这样:

total = 0
for chromosome in member[chromosomes]:
    for epoc in epocs:
        thisValue = Calc(epoc,chromosome)
        total = total + abs(thisValue - getRealValue(epoc))

函数Calc获取染色体和epoc值并输出一个浮点数。

零是一个完美的分数。分数越高,会员越差。我平均所有成员得分并删除低于平均水平的成绩。

我尝试对来自数据库的静态数据集进行评分,并且我已尝试对过去24小时进行动态评分 - 这意味着过去24小时始终与时间流量不同。我也尝试了过去4小时,最后一小时和过去3天。

变异系统

我已将突变率设定为2%,但我已经以更高的百分比发挥作用,结果更糟。只有儿童才有可能发生变异,而不是现有的人口(想留住精英)。当选择一个孩子进行突变时,它的染色体中的值随机移动(加或减)随机移动一个小数,在0到1之间,最多100个小数位。这为孩子的价值观提供了一点点改变 - 因为一个非常微小的变化会彻底改变染色体功能的输出。

我的问题

我现在使用的交叉方法会导致早熟收敛。

我尝试过的交叉策略

我尝试从每个父母那里随机抽取随机染色体数。我尝试过第一个父母的前半部分和第二个父母的后半部分。 到目前为止,我已尝试过这些方法:

# Number of chromosomes from parent 1.
parent1chromosomes = randomNumber(0,len(parent1['chromosomes']))

# Number of chromosomes from parent 2.
parent2chromosomes = randomNumber(0,len(parent2['chromosomes']))

child = {}
child['chromosomes'] = []

# Get parent 1 chromosomes into child.
for i in range(0,parent1chromosomes):
    child['chromosomes'].append(random.choice(parent1['chromosomes']))

# Get parent 2 chromosomes into child.
for i in range(0,parent2chromosomes):
    child['chromosomes'].append(random.choice(parent2['chromosomes']))

注意:randomNumber是一个返回指定范围之间的随机整数的函数。

这两种尝试都会导致早期收敛。我试图解决的问题非常复杂 - 到目前为止,我已尝试过10,000到1,000,000的人口规模。

示例效果

这是最近一次跑步的屏幕截图。我映射了最佳分数(最低分)和平均分数。在这张照片中,它绘制了五个不同人群的最佳和平均值。这些特殊的5个群体每个10,000个成员使用3秒的实际数据抽样,并且动态地对最后一小时的实际数据进行评分 - 这就是为什么最好的情况变得更糟 - 因为它被评分的真实数据被改变了以一种让最好的成员变得更糟的方式。最好的分数是数千,这是完全不准确的。较小的人口导致较快的早期收敛。

enter image description here

我的问题

有哪些其他方法可以更好地处理可变长度成员的交叉,其中染色体的顺序无关紧要,重复的染色体无关紧要?

2 个答案:

答案 0 :(得分:3)

而不是:

for i in range(0,parent1chromosomes):
    child['chromosomes'].append(random.choice(parent1['chromosomes']))

也许:

child['chromosomes'].extend(random.sample(parent1['chromosomes'], parent1chromosomes))

这意味着如果您从父母一方获得染色体,或者从父母双方获得一份副本,您只能获得重复的染色体。

答案 1 :(得分:1)

免责声明: 此答案可能会根据您的反馈进行连续改进。

所以,我们想解决两个问题:

  • 快速收敛:人口多样性下降得太快
  • 遗传过时:健身功能会随着时间的推移而变化,这使得早期成功的个体从长远来看可能会放松,而从长远来看,早期不成功的个体潜在获胜者也是如此。

在您的方案中,在每一轮中,您保留您所在群体中的最佳人选。原则上,这通常是一个好主意:人们不希望失去最优解的最佳近似。但是,从一轮到下一轮(全球人口)保持的个体越多,人口中的多样性就越快。这是因为保持个体存活会使他的基因组有更高的传播机会,并且这会在多轮中以指数速率发生。因此,与整个人口相比,从一轮到下一轮保持活力的个体比例要么非常小,要么为零。

或者,您可以通过增强突变率来补偿快速收敛,从而实现更高的多样性。在这方面,您可能需要考虑使用两种不同的变异方法:

  • 强烈突变:这会以任意方式改变一些值,以便在群体中引入(或重新引入)尚未获得的基因。有几种方法可以执行此操作: 1。一个(或多个)新key-value对被任意删除引入在孩子的基因组中 2。现有key对的valuekey-value以任意方式更改,与您正在进行的操作类似现在翻一下

  • 弱变异:鉴于您的健身功能的性质,随着时间的推移改变其得分评估,任意{{1}可能是明智的使用alter计算的某些数值,例如 %对增加/减少key-value。这应该使您的人口更容易适应时间流量,但我必须提到,应该非常谨慎地选择所选择的变化率,以便不支配搜索或使其不稳定。 / p>

这里真正的大象是遗传过时。想象一下,你的问题是离散而不是连续体,你必须及时找到最佳个人的固定点而不是 >"由于健身功能的变化,沿着搜索发展" 。然后,在前一种情况下,人们要做的是为适应度函数运行0.00000001%不同权重的单独搜索。每次,一个人将从完全随机的群体开始,然后允许遗传算法收敛于最优解。现在采取一个非常大的N,足够大,以便搜索收集重叠所需的时间与您想要评估的几个下一个时间点重叠,并尝试重叠所有保留的总体人口搜索..你得到了什么?你得到的群体具有很高的多样性,因为几个重叠的搜索刚刚开始!

因此,如果您现在想要将离散案例扩展到连续体,则必须复制相同的情况:每轮或固定后(和小) )轮数,您应该生成一组新的随机个体,就像在初始化步骤一样,并给它们一个繁殖的机会。这需要谨慎进行,因为新的人口是完全随机的,它可能会在短短几轮内被现有的人口完全淹没。一个想法可能是让新的随机数据库在一个安全的避风港中被改进,然后再对主要的个人群体进行评估。在几轮之后,可以允许两个池彼此繁殖,然后在一个独特的群体中合并,以便可以创建一组新的随机个体。