简单的遗传算法,用于浮点数列表



我当前正在尝试制作一种遗传算法,以将浮点号列表匹配到另一个浮点数列表(我知道这是"毫无意义"的,因为我已经有了数据,但我只想在尝试解决更复杂的遗传算法问题之前能够做到这一点)。我有以下用Python编写的代码。

from random import random
ofInterest = [
                5.76260089714,
                7.87666520017,
                9.53163269149,
                9.72801578613,
                5.20002737716,
                0.50133290228,
                8.58820041647,
                9.65056792475,
                3.07043110493,
                1.13232332178
              ]
print(ofInterest)
fits = []
for i in range(100):
    fits.append([])
    for j in range(10):
        fits[i].append(random()*10)
fitness = []
for i in range(100):
    fitness.append(100000000)

def makeFitnessList():
    for i in range(100):
        fitValue = 0
        for j in range(10):
            fitValue += (fits[i][j] - ofInterest[j])**2
        fitness[i] = fitValue
topTenFitness = []
for i in range(10):
    topTenFitness.append(10000000000000)
print(topTenFitness)
def sortByFitness():
    makeFitnessList()
    temp = []
    count = 0
    while len(temp) < 10:
        k = 100000000000000000000000000
        index = -1
        for i in range(len(fitness)):
            if k > fitness[i]:
                k = fitness[i]
                index = i  
        temp += [index]
        topTenFitness[count] = fitness[index]
        print(fitness[index])
        fitness[index] = 1000000000000
        count += 1
    temp2 = fits
    for i in range(10):
        fits[i] = temp2[temp[i]]
#sortByFitness()
#print(fitness[0])
#print(fits[0])
def cross(rate):
    for i in range(10,100):
        parent1Place = int(random()*10.01)
        if (i*random()) > rate:
            parent2Place = int(random()*10.01)
            crossPoint = int(random()*10.01)
            for i in range(crossPoint):
                tempOne = fits[parent1Place][i]
                tempTwo = fits[parent2Place][i]
                fits[parent1Place][i] = tempOne
                fits[parent2Place][i] = tempTwo
        else:
            fits[i] = fits[parent1Place]

def mutate(rate):
    for i in range(10,100):
        for gene in range(10):
            if random() < rate:
                fits[i][gene] = random()*10
for i in range(10):
    makeFitnessList()
    sortByFitness()
    print("")
    cross(.6)
    mutate(.4)
sortByFitness()
print(fits[0])

此程序运行,但健身没有收益:

158.551483202
89.0049309654
150.062479048
223.447907282
162.41893599
105.727706028
169.756843723
77.0767420744
122.905567656
144.328292984
113.405444904
132.748651766
144.739705127
155.959141194
151.507885923
86.3246751862
etc...

如果使用numpy,所有计算都更容易,并且应该尝试变得更加柔软:

import numpy as np
ofInterest = np.array([
                5.76260089714,
                7.87666520017,
                9.53163269149,
                9.72801578613,
                5.20002737716,
                0.50133290228,
                8.58820041647,
                9.65056792475,
                3.07043110493,
                1.13232332178
              ])
print(ofInterest)
fits = np.random.random((100,10)) * 10
def sortByFitness():
    global fits
    fitness = np.sum((fits - ofInterest)**2,axis=1)
    fits = fits[fitness.argsort()]
def cross(rate):
    for i in range(10,100):
        parents = fits[np.random.random_integers(0,9,2)]
        if (i*np.random.random()) > rate:
            crossPoint = np.random.random_integers(0,10)
            fits[i] = np.hstack((parents[0,:crossPoint],parents[1,crossPoint:]))
        else:
            fits[i] = parents[0]
def mutate(rate):
    for i in range(10,100):
        for gene in range(10):
            if np.random.random() < rate:
                fits[i][gene] = np.random.random()*10
for i in range(100):
    sortByFitness()
    cross(.6)
    mutate(.4)
print(fits[0])

这可能会导致不良结果:

  1. 您的突变率太高了。每个基因的40%意味着每个个体有10个基因的平均4个变化。实际上,您应该选择突变率,以便每一代人在整个人群中仅引入少数突变。

  2. 您的cross功能交换了所选父母之间的基因,而不是让父母不变,并将父母双方的基因的分数复制到一个新创造的孩子。

  3. 如果您突变基因,则由新的独立随机变量代替。这是无效的,因为它使算法在其上运行的景观非常粗糙。如果您仅在原始值中添加小的随机变量,例如在[-0.1,0.1]。

  4. 而不是选择基因组的跨点,而是在父母之间完全随机选择基因会更有效,因为基因的顺序在您的模型中没有意义。

  5. 您的等待时间不够长,10代不会带您远。

  6. 据我所知,您无法正确衡量健身的增益。您应该打印出人口的平均健身(也许是TOP10的最佳健身或平均水平)。

只是遗传算法很有趣...:)

import random
target_list = [1,2,3,4,5,6,7,8,9,10]
size_of_individual = len(target_list)
size_of_population = 100
n_generations = 10000
def score_fitness(individual):
    return sum((val-target)**2 for val,target in zip(individual,target_list))
def create_individual():
    return [random.random()*10 for _ in range(size_of_individual)]
def crossover(individual1,individual2):
    return [val1 if random.random() < 0.5 else val2 for val1,val2 in zip(individual1,individual2)]
def mutate(individual,mutation_chance=0.1,mutation_size = 0.1):
    def get_mutation(val):
         return val if random.random()>mutation_chance else val + [-mutation_size,mutation_size][random.random()<0.5]
    return [get_mutation(val) for val in individual]
def selection_step(sorted_old_population):
    def select_one():
        while True:
            candidate_idx = random.randint(0,len(sorted_old_population)-1)
            if random.randint(0,len(sorted_old_population))>= candidate_idx:
                return sorted_old_population[candidate_idx]
    selections = [select_one(),select_one()]
    while selections[1] == selections[0]:
        selections[1] = select_one()
    return selections
def create_new_population(old_population,elitism=0):
    sorted_population = sorted(old_population,key= score_fitness)
    print "BEST OLD:",sorted_population[0],score_fitness(sorted_population[0])
    print "AVG OLD:", sum(score_fitness(i) for i in sorted_population)
    new_population = sorted_population[:elitism]
    while len(new_population) < size_of_population:
          new_population.append(mutate(crossover(*selection_step(sorted_population))))
    return new_population[:size_of_population]

population = [create_individual() for _ in range(size_of_population)]
for i in range(n_generations):
    population = create_new_population(population,5)

请记住,这对于遗传算法是一个糟糕的问题,而且还有很多改进的空间(即一起摆脱精英主义)

最新更新