【发布时间】:2019-10-30 23:02:21
【问题描述】:
我正在 C# WinForms 中实现遗传算法,以找到一个非常简单的数学方程的最优解。这里的“简单”一词意味着方程必须具有以下性质:
- 仅由整数正数组成
- 等式的最终结果必须是小于 1001 的正数
- 允许最少 2 个变量,最多 7 个变量
- 每个变量的系数必须在 1 到 10 之间(包括下限和上限)
- 变量值从 0 到 500
- 只允许添加
有人会说,我认为方程式如此“简单”,我将能够达到最佳解。但是,我总是只能得到一个非常接近最优解的解。为了评估解决方案是否最优,我使用以下公式:
f(x) = absolute((sum_of_all_variables) - equation_result)
例如,我有以下等式:
1a + 1b = 12
如果a 是2 并且b 是3,则该个人的f(x) 将是abs(2 + 3 - 12) = 7。当f(x) 到达0 或者我已经生成了 50 代时,我的代码就会停止。
我目前的突变率是 50%,我目前的交叉率是 25%。使用的选择方法是轮盘赌选择。突变方法是随机突变,即我只是在我的基因库中随机选择一个基因来改变它的值,每代最多改变50%的基因。
我的期望:代码生成的解决方案(个人)的 f(x) 值为 0,这是可用的最佳解决方案之一。
当前结果:代码产生的解决方案几乎是最优的。 我发现的一个常见模式是,几乎最佳的解决方案通常会在下一代中完全复制。
我现在对问题的猜测:
我认为这与我如何跨界有关。我要跨界做什么:
- 为每个人分配一个随机值
- 如果所述随机值小于交叉率,则保存该个人的数据以供以后用于交叉
- 收集所有要交叉的个体后,我为每个个体随机选择一个交叉点
- 我认为这是问题所在:我在第一个个体上与第二个个体进行交叉,将第一个个体的基因和第二个将要交叉的个体的基因合并-ed。然后,继续第二个人和第三个人,依此类推。最后一个人将与第一个人交叉。
但是,正如我所说,它不会产生最佳结果。是我的逻辑有问题,还是遗传算法在这个简单的数学方程上的预期行为?
我用于参考的交叉方法(我使用 C# WinForms 在 ListView 中显示数据):
private static void Crossover(List<Chromosome> chromosomes, Random seed)
{
List<int> crossoverChromosome = new List<int>();
for (int i = 0; i < 50; i++)
{
decimal randomedValue = RandomizeValue(seed);
if (randomedValue < Population.CrossoverRate) crossoverChromosome.Add(i);
}
for (int i = 0; i < crossoverChromosome.Count; i++)
{
int crossoverPoint = seed.Next(0, chromosomes[0].GeneValues.Count);
chromosomes[crossoverChromosome[i]] = chromosomes[crossoverChromosome[i]].MixChromosome(chromosomes[crossoverChromosome[(i + 1) % crossoverChromosome.Count]], crossoverPoint);
}
}
private static decimal RandomizeValue(Random seed)
{
return Math.Round((decimal)seed.NextDouble(), 5);
}
public Chromosome MixChromosome(Chromosome mixture, int crossoverPoint)
{
List<Gene> newGenes = new List<Gene>();
newGenes.AddRange(this.GetGenes(0, crossoverPoint));
newGenes.AddRange(mixture.GetGenes(crossoverPoint, this.GeneValues.Count));
return new Chromosome(DesiredValue, OperatorData, newGenes); // Ignore the DesiredValue and Operator Data, it has nothing to do with crossover
}
private List<Gene> GetGenes(int firstIndex, int lastIndex)
{
List<Gene> slicedGenes = new List<Gene>();
for (int i = firstIndex; i < lastIndex; i++)
{
slicedGenes.Add(Genes[i].CloneGene());
}
return slicedGenes;
}
我只对包含两个变量的方程进行了大量测试。
编辑
附加信息:
- 我不使用精英主义
- 初始种群规模 = 50 人
- 每代人口规模 = 50 人
在方程 1a + 1b = 10 上重新运行 10 次会在 50 代后产生以下最佳适应度值:
- 第一次重播:24
- 第二次重播:11
- 第三次重播:42
- 第四次重播:13
- 第五次重播:5
- 第六次重播:19
- 第七次重播:7
- 第八次重播:1
- 第九次重播:6
- 第十次重播:29
- 每次重新运行的附加信息:在 50 代中产生最佳适应度值的染色体在种群中经常重复。例如,在第八次重新运行时,我发现染色体上出现了很多值为
a4,值为b7。
【问题讨论】:
-
有许多参数在构建遗传算法中发挥作用。通常会涉及大量的试错,即使这样,由于随机性,也不能保证找到最佳答案。如果您清楚地说明您正在使用的所有参数,您的问题可以得到改善。例如:初始人口有多大?你使用任何一种精英主义吗?你跑了多少次,跑步的典型/最佳/最差适应性是什么?
-
@tucuxi 我添加了更多信息。请看一看。
-
您只发布了一小部分代码,问题很可能是您如何为这个特定问题定义类或您如何调用您发布的方法。您最好只发布minimal reproducible example。理想情况下,这还包括对您的代码正在执行的操作的详细高级描述。虽然通常这些问题最好通过调试来解决,看看你的代码在做什么。但是 50% 的突变率是巨大的 - 这应该低于 10%,可能接近 1%。
-
@Dukeling 我将我的突变率调整为 50%,因为每次重新运行的最后一代(第 50 代)中的所有染色体都大量重复(超过 50%)。即使突变率如此之高,我仍然有大量重复最接近 f(x) = 0 的相似染色体。我认为我的解决方案正在收敛到局部最大值解决方案,而不是全局最大值。
标签: algorithm genetic-algorithm