首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让我的价值世代适用于我的遗传算法(Python)

如何让我的价值世代适用于我的遗传算法(Python)
EN

Stack Overflow用户
提问于 2021-03-02 01:48:19
回答 1查看 78关注 0票数 1

我已经创建了一个遗传算法来解决观看节目的问题,通过使用受Kie代码启发的代码,并遵循此视频https://www.youtube.com/watch?v=nhT56blfRpE中的代码,以什么顺序最大化剩余

不幸的是,我无法让生成部分工作,它导致结果中有0代,即使它创建了一个每次运行时都不同的解决方案。我拥有的变量是名称、体能和体重,它们转化为节目的名称、评分和剧集数量。至于生成部分代码将无法工作,这也不会考虑到程序创建最优解所需的时间。

代码语言:javascript
复制
from random import choices, randint, randrange, random #allows for a random creations to be made
from typing import List, Callable, Tuple #allows to use list functions and callable
from collections import namedtuple #allows the use for named tuple
import time #allows for time to be used
from functools import partial #allows for partial to be used

Genome=List[int]
Population=List[Genome]
FitnessFunc=Callable[[Genome],int] #puts the fitness with the genome
PopulateFunc=Callable[[], Population]#gives out new solutions
SelectionFunc=Callable[[Population, FitnessFunc], Tuple[Genome,Genome]] #takes the population and fitness to make select for a new solution
CrossoverFunc=Callable[[Genome, Genome], Tuple[Genome,Genome]]#takes two genomes and produces two genomes
MutationFunc=Callable[[Genome], Genome]#takes a genome and sometimes produces a new genome
PrinterFunc=Callable[[Population, int, FitnessFunc], None]
#puts the functions into perameters 
Thing=namedtuple('Thing',['name','value','weight'])#gives a structure for the list below

things=[
    Thing('Seishun Buta Yarou wa Bunny Girl Senpai no Yume wo Minai (TV)',8.38,13),
    Thing('Bakemonogatari',8.36,15),
    Thing('Kodomo no Jikan (TV)',6.82,12),
    Thing('Tsuki ga Kirei',8.18,12),
    Thing('Tokyo Ravens',7.53,24),
    Thing('Kono Subarashii Sekai ni Shukufuku wo!',8.15,10),
    Thing('Shingeki no Kyojin S4',9.2,12),
    Thing('Dr Stone S2',8.33,11),
    Thing('The Promised Neverland',8.11,11),
    Thing('Re:Zero',8.7,12),
    Thing('Toradora!',8.24,25),
    Thing('Sousei no Onmyouji',7.33,50),
    Thing('Rurouni Kenshin: Meiji Kenkaku Romantan',8.31,94),
    Thing('Fullmetal Alchemist: Brotherhood',9.2,64),
    Thing('Steins;Gate',9.11,24),
    Thing('Boku no Pico',4.31,3)
]

def generate_genome(length: int) -> Genome:
    return choices([0,1], k=length)
    #creates a random genome 
##genome

def generate_population(size: int, genome_length: int) -> Population:
    return [generate_genome(genome_length)for _ in range(size)]
    #generates a list of genomes
##population

def fitness(genome: Genome, things: things, weight_limit: int) -> int:
    if len(genome)!=len(things):#checks if the two are the same length
        raise ValueError("genome and things must be of the same length")

    weight=0
    value=0

    for i, thing in enumerate (things):
        if genome[i]==1:
            weight+=thing.weight
            value+=thing.value #adds the weight values and fitness values
            
            if weight>weight_limit: #checks if the genome is under the weight limit
                return 0
    return value
#fitness function

def selection_pair(population: Population, fitness_func: FitnessFunc) -> Population:
    return choices(
        population=population,
        weights=[fitness_func(genome) for genome in population],
        k=2 #draw twice (two parents)
    )
#selection function

def single_point_crossover(a: Genome,b: Genome) -> Tuple[Genome,Genome]:
    if len(a)!=len(b):
        raise ValueError("Genomes a and b must be of same length")
    #checks the size of the genomes that was selected
    #the genomes have to be the same in length or it will not work

    length=len(a)
    if length<2:#checks the length as they would have to be at least 2 or else you are unable to cut them in half
        return a,b

    p=randint(1, length-1)#randomly takes parts of the two genomes
    return a[0:p]+b[p:],b[0:p]+a[p:]#and then creates them
#crossover function

def mutation(genome: Genome, num: int=1, probability: float=0.5) -> Genome:
    for _ in range(num):
        index=randrange(len(genome))#if the number made is higher than the probability it is left alone
        genome[index]=genome[index] if random() > probability else abs(genome[index]-1)#makes the absolute value so that it is either 1 or 0
        #people hatee this one but why ^^
    return genome
#mutation function

def run_evolution(
    populate_func: PopulateFunc,
    fitness_func: FitnessFunc,#for these two it populates with variables
    fitness_limit: int,#if the fitness limit is reached then the program is done
    selection_func: SelectionFunc=selection_pair,
    crossover_func: CrossoverFunc=single_point_crossover,
    mutation_func: MutationFunc=mutation,# initialises the above three
    generation_limit: int=100 #limits on how much is made
) -> Tuple[Population, int]:
    population=populate_func()#populates with random genomes

    for generations in range(generation_limit):
        population=sorted(
            population, 
            key=lambda genome: fitness_func(genome),
            reverse=True
            #sorts the fitness of the genomes so that the higher number is at the start
        )
        if fitness_func(population[0])>=fitness_limit:
            break
        #if the fitness limit is reached then the program ends (breaks)

        next_generation=population[0:2]#gets the top two genomes for the next generation

        for j in range(int(len(population)/2)-1):
            parents=selection_func(population, fitness_func) #gets the top two to be made as parents
            offspring_a, offspring_b=crossover_func(parents[0], parents[1]) #puts the genomes into seprate variables
            offspring_a=mutation_func(offspring_a)
            offspring_b=mutation_func(offspring_b)#creates a mutation for both genomes randomly
            next_generation+=[offspring_a, offspring_b]
            #creates the next genomes and puts them into population
        population=next_generation

    population=sorted(
         population, 
         key=lambda genome: fitness_func(genome),
        reverse=True
       #sorts the fitness of the genomes so that the higher number is at the start
    )

    return population, generations
#evolutionary main loop

def genome_to_things(genome: Genome, things: things) -> things:
    result=[]
    for i, thing in enumerate(things):
        if genome[i]==1:
            result+=[thing.name]

    return result 
#collects the best solutions so that it may be printied out for later  


start=time.time()
population, generations=run_evolution(
    populate_func=partial(
        generate_population, size=10, genome_length=len(things)
    ),
    fitness_func=partial(
        fitness, things=things, weight_limit=94
    ),
    fitness_limit=10,
    generation_limit=100
)
end=time.time()
#runs the program

print(f"number of generations: {generations}")
print(f"time: {end-start}s")
print(f"best solution: {genome_to_things(population[0], things)}")
#prints results
EN

回答 1

Stack Overflow用户

发布于 2021-05-17 19:28:15

这意味着你的遗传算法直接在第一个初始第0代中找到一个满足你的适应度限制的解决方案。

如果我用fitness_limit=100运行你的代码,我会得到以下输出。

代码语言:javascript
复制
number of generations: 99
time: 0.014637947082519531s
best solution: ['Seishun Buta Yarou wa Bunny Girl Senpai no Yume wo Minai (TV)', 'Bakemonogatari', 'Tsuki ga Kirei', 'Kono Subarashii Sekai ni Shukufuku wo!', 'Shingeki no Kyojin S4', 'Dr Stone S2', 'Re:Zero', 'Boku no Pico']
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66427049

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档