我从头开始编写了一个具有所有特征(锦标赛选择,交叉,变异,精英等)的遗传算法,它成功地演变了“计数问题”的解决方案 - 即它操纵随机生成的二进制染色体群体由1s和1组成0到达一个完美的1到1。
现在我需要应用该算法并创建一个分类器。系统应将二进制数据分类为类“0”或类“1”。我有一些训练数据,但这里是最基本的:
32 rows x 5 variables (+ class, space separated, CR EOL)
00000 0
00001 0
00010 0
00011 1
00100 0
00101 1
00110 1
00111 0
01000 0
01001 1
01010 1
01011 0
01100 1
01101 0
01110 0
01111 1
10000 0
10001 1
10010 1
10011 0
10100 1
10101 0
10110 0
10111 1
11000 1
11001 0
11010 0
11011 1
11100 0
11101 1
11110 1
11111 0
我将如何将基于规则的上下文建立的遗传算法应用于IF x(AND y)那么z?我不知道从哪里开始,我想我可能需要做一些规则提取,但我不知道如何在这种情况下这样做。
编辑:进一步的代码
public class Controller {
public static void main(String[] args) {
final int P = 50; // population size
final int N = 32; // chromosome length
final double C = 0.95; // crossover rate
final double M = (double) 1 / P; // mutation rate
final int G = 50; // # of generations
GA ga = new GA(P, N, C, M);
// Initialise population of random individuals
Individual[] population = ga.initPop();
// "Counting ones" fitness evaluation
System.out.println("GEN0");
ga.evaluatePop(population);
ga.printFitness(population);
int generation = 1;
for (int i = 0; i < G; i++) {
System.out.println("\nGeneration: " + generation);
// Tournament selection
population = ga.tournament(population);
// Tournament winners fitness evaluation
ga.evaluatePop(population);
// Single-point crossover
population = ga.crossover(population);
// Crossover children fitness evaluation
ga.evaluatePop(population);
// Bit-wise mutation
population = ga.mutate(population);
// Post-mutation population fitness evaluation
ga.evaluatePop(population);
// Elitism replacement (remove the worst gene and replace with a copy of the best)
population = ga.elitism(population);
// Post-elitism population fitness evaluation
ga.evaluatePop(population);
ga.printFitness(population);
generation++;
if (ga.bestFitness(population) == N) {
break;
}
}
}
`
public class GA {
int populationSize;
int chromosomeSize;
double crossoverRate;
double mutationRate;
Random random = new Random();
public GA(int populationSize, int chromosomeSize, double crossoverRate, double mutationRate) {
this.populationSize = populationSize;
this.chromosomeSize = chromosomeSize;
this.crossoverRate = crossoverRate;
this.mutationRate = mutationRate;
}
public Individual[] initPop() {
Individual[] population = new Individual[populationSize];
for (int i = 0; i < populationSize; i++) {
population[i] = new Individual(chromosomeSize);
}
return population;
}
public void evaluatePop(Individual[] population) {
for (int i = 0; i < population.length; i++) {
population[i].evaluate();
}
}
public Individual[] tournament(Individual[] population) {
Individual[] selectionTemp = new Individual[populationSize];
for (int i = 0; i < population.length; i++) {
Individual parent1 = population[random.nextInt(population.length)];
Individual parent2 = population[random.nextInt(population.length)];
if (parent1.getFitness() >= parent2.getFitness()) {
selectionTemp[i] = parent1;
} else {
selectionTemp[i] = parent2;
}
}
population = selectionTemp;
return population;
}
public Individual[] crossover(Individual[] population) {
for (int i = 0; i < population.length - 1; i += 2) {
Individual offspring1 = new Individual(population[0].getChromosome().length);
Individual offspring2 = new Individual(population[0].getChromosome().length);
int xpoint = 1 + random.nextInt(chromosomeSize - 1);
if (random.nextDouble() < crossoverRate) {
for (int j = 0; j < xpoint; j++) {
offspring1.setGene(j, population[i].getGene(j));
offspring2.setGene(j, population[i+1].getGene(j));
}
for (int j = xpoint; j < population[0].getChromosome().length; j++) {
offspring1.setGene(j, population[i+1].getGene(j));
offspring2.setGene(j, population[i].getGene(j));
}
}
population[i] = offspring1;
population[i+1] = offspring2;
}
return population;
}
public Individual[] mutate(Individual[] population) {
for (int i = 0; i < population.length; i++) {
for (int j = 0; j < population[i].getChromosome().length; j++) {
if (random.nextDouble() < mutationRate) {
population[i].mutate(j);
}
}
}
return population;
}
public Individual[] elitism(Individual[] population) {
Individual min = population[0];
int minOffset = 0;
for (int i = 0; i < population.length; i++) {
if (population[i].getFitness() <= min.getFitness()) {
min = population[i];
minOffset = i;
}
}
Individual max = population[0];
int maxOffset = 0;
for (int i = 0; i < population.length; i++) {
if (population[i].getFitness() >= max.getFitness()) {
max = population[i];
maxOffset = i;
}
}
population[minOffset] = population[maxOffset];
return population;
}
// <editor-fold defaultstate="collapsed" desc="Debug logic...">
public int totalFitness(Individual[] population) {
int population_fitness = 0;
for (int i = 0; i < population.length; i++) {
population_fitness += population[i].getFitness();
}
return population_fitness;
}
public double avgFitness(Individual[] population) {
return (double) totalFitness(population) / population.length;
}
public int bestFitness(Individual[] population) {
int max = population[0].getFitness();
for (int i = 0; i < population.length; i++) {
if (population[i].getFitness() > max) {
max = population[i].getFitness();
}
}
return max;
}
public Individual bestIndividual(Individual[] population) {
Individual max = population[0];
for (int i = 0; i < population.length; i++) {
if (population[i].getFitness() >= max.getFitness()) {
max = population[i];
}
}
return max;
}
public void printFitness(Individual[] population) {
System.out.println("Total fitness: " + totalFitness(population));
System.out.println("Average fitness: " + avgFitness(population));
//System.out.println("Best fitness: " + bestFitness(population));
System.out.println("Best individual: " + bestIndividual(population));
}
public void printPop(Individual[] population) {
for (int i = 0; i < population.length; i++) {
System.out.println(Arrays.toString(population));
}
}
// </editor-fold>
``
public class Individual {
public int[] chromosome;
public int fitness = 0;
Random random = new Random();
public Individual(int chromosomeSize) {
this.chromosome = new int[chromosomeSize];
for (int i = 0; i < chromosomeSize; i++) {
this.setGene(i, random.nextInt(2));
}
}
// Initializes individual with a blank chromosome (all genes 0)
public Individual(int chromosomeSize, boolean isBlank) {
this.chromosome = new int[chromosomeSize];
Arrays.fill(chromosome, 0);
}
public void mutate(int offset) {
if (this.getGene(offset) == 1) {
this.setGene(offset, 0);
} else {
this.setGene(offset, 1);
}
}
public void evaluate() {
int count = 0;
for (int offset = 0; offset < this.chromosome.length; offset++) {
if (this.getGene(offset) == 1) {
count++;
}
}
this.setFitness(count);
}
public int getGene(int offset) {
return this.chromosome[offset];
}
public void setGene(int offset, int gene) {
this.chromosome[offset] = gene;
}
public int[] getChromosome() {
return chromosome;
}
public int getFitness() {
return fitness;
}
public void setFitness(int fitness) {
this.fitness = fitness;
}
@Override
public String toString() {
String output = "Binary gene representation: ";
for (int i = 0; i < this.chromosome.length; i++) {
output += this.getGene(i);
}
System.out.println(output);
System.out.println("Fitness: " + this.getFitness());
return output;
}
答案 0 :(得分:1)
遗传算法(GA)是受自然选择过程启发的元启发式。 元启发式被定义为更高级别的过程或启发式,旨在查找,生成或选择子启发式,或子启发式的组合或置换。使用GA本身不会告诉您子启发式应该是什么样子或者什么。因此,您可以将您当前的实现重新表述为:
我已经开发了GA metaheursiticite框架,但是现在我需要确定并设计可能允许我解决这个特定问题的子启发式算法。我想我只做了一半。
那是对的。现在,对于关于GA的第二个重要理解:它们最适用于可以进一步细化部分成功(子解决方案或非最佳解决方案)以获得更好结果的问题。 < / p>
GAs可以很好地解决数学优化问题,例如,通常存在连续性和局部性。或者解决一个迷宫,例如,一个好的部分解决方案绝对是尝试完整解决方案的一个不错的起点。
不幸的是,在您的特定情况下,奇偶校验位问题(偶数或奇数问题)不是优化问题或明显的迭代问题。这是一个全有或全无的问题,GA不适合0
或1
二元染色体。
这并不意味着您无法强制使用GA解决方案 - 您可以创建使用模数或XOR(例如)的各种查找规则,并且可以非常快速地发展可行的解决方案。但它几乎感觉像作弊,因为你硬编码了必要的&#34;洞察力&#34; (模运算或异或运算)您希望进化。将GA归入解决方案的另一种方法是开发基因&#34;代码为&#34; programmatic&#34;语法并实际演化一个小程序函数bool result = f(x)
,它会输出一个真值或假值(你的二进制分类)。但是这增加了很多复杂性,如语法等,你最终可能会进入STGP(强类型遗传编程)领域,你应该知道居住在那里的当地人会对你传递严重的时间税。通过他们的土地毫无准备。
我对奇偶校验问题的建议:降低自己只使用神经网络。他们不是那么性感或普遍,但他们会完成工作而不需要你作弊或做更多的工作(STGP)。众所周知,具有足够数量节点的神经网络可以学习XOR,从而学习奇偶校验。
修改强>
要将此作为GA学校作业归类,我建议采用数字门式方法。您需要从二进制染色体方案转变为三元染色体方案(由于您已使用int[] chromosome
声明,因此不需要额外的编码)。然后,每个trit(三位数)可以编码以下查找规则:
1: prior State AND B[next]
2: prior State OR B[next]
3: NOT
对于给定的输入位模式B[]
,可以按位从左到右评估三元染色体,初始State
变量为0
(其中{ {1}}是评估函数内部的内部变量,并且在每个连续的trit之间发生隐式AND操作(NOT类型除外)。因此,例如,假设您演化了三元解State
,它将代表评估函数中的以下操作序列(对每个输入位应用一次):
2, 3, 3, 1
其中((!(!(prior State | B[next]))) & (prior State & B[next]))
和State
显然是位(B[next]
)变量。请注意,中间附近的AND操作来自我们定义的任何非NOT类型的trits之间的隐式AND操作。例如,输入位字符串bool
在针对我们的示例染色体100
运行评估函数时将如下所示:
2, 3, 3, 1
如果你喜欢的话,你可以任意定义0的结果来表示偶数,将1的结果定义为奇数。选择并不重要,因为GA可以很容易地学会在染色体末端用额外的非trit来反转结果。
这个评估函数的优点在于它将处理任意长的输入位串,因为它仅以滚动方式每位应用,而不关心整个位串长度。我们知道它理论上可以演变出正确的解决方案,因为1. State = 0
2. B[next] = 1, State = ((!(!(0 | 1))) & (0 & 1)) = 0
3. B[next] = 0, State = ((!(!(0 | 0))) & (0 & 0)) = 0
4. B[next] = 0, State = ((!(!(0 | 0))) & (0 & 0)) = 0
5. Return final State value (0 here) from evaluation function.
和XOR是奇偶校验所需的全部。
为了使其起作用,你必须允许可变长度的解决方案(可变长度进化的trit序列),但是将染色体限制在合理的上限(比如15 trits左右)以防止GA进入疯狂的解决方案。另外还有一件事需要做才能实现:基于对许多输入位串的批量评估进行评分。由于任何输入位串的求值函数输出仅为A XOR B = (A OR B) AND (NOT (A AND B))
或0
,因此结果将是100%正确或0%正确。这本身并不允许有用的健身评分,因为你没有比较好地对不同的trit序列(解决方案)进行排序的方法,因为大约一半将是100%正确而另一半将是0%。但解决方案很简单:只需对每个正确标记的所有输入字符串的百分比进行评分。因此,如果数据集中有100个输入位串,并且解决方案1正确标记了57%的输入位串,而解决方案2仅正确标记了49%的输入,那么现在您可以对解决方案填充进行排序并选择用于遗传交换,突变,精英生存等等。