此前使用deap库提供的遗传算法,后发现几个不便之处
1.需要对特征进行编码,还需要对编码溢出情况进行处理
2.交配的算法每次都交换连续的一段基因
因此基于遗传算法的基本思路,写了新的遗传算法,进行了小优化:
较传统遗传算法的区别
1.适应度这里固定成了单向增大为适应
2.不用再给特征编码就能实现变异,特征分为两类,第一类是在一个范围内取值的连续变量,第二类是离散的在list中选择,详见tez类定义
使用方法:改写calfit函数变成自己的算法之后就能使用(注意适应度增大原则)
下面是所有的源代码,大家可以根据自己的需要进行使用和改写,代码结尾注释掉的几行是一个调用的例子,大家可以参考
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 18 20:29:24 2024
@author: trader tom
"""
'''
新遗传算法
较传统遗传算法的区别
1.适应度这里固定成了单向增大为适应
2.不用再给特征编码就能实现变异,特征分为两类,第一类是在一个范围内取值的连续变量,第二类是离散的在list中选择,详见tez类定义
使用方法:改写calfit函数变成自己的算法之后就能使用(注意适应度增大原则)
'''
import random
import numpy as np
class tez:#特征类
def __init__(self,fanwei:'一个list,可以是范围的两个数字,也可以是包含所有元素的list',model:'int 1为范围内任意数字,2为一个list随机选'):
self.model=model
self.fanwei=fanwei
def born(self):#给value赋值
if self.model==1:
self.value=random.uniform(min(self.fanwei), max(self.fanwei))
else:
self.value=random.choice(self.fanwei)
class getis:#个体类 类
def __init__(self,ltz:'特征的信息:list([特征范围,model])'):
self.ltz=[tez(i[0],i[1]) for i in ltz]#把特征实例化
def born(self):#随机生成个体
[tz.born() for tz in self.ltz]
return [tz.value for tz in self.ltz]
def bianyi(self,n):#参数是特征的索引,完成特征变异
self.ltz[n].born()
return self.ltz[n].value
class geti:#个体类
def __init__(self,value:'特征的值的list',father:'getis类'):
self.value=value
self.fit=False#最开始的时候个体没有适应度
self.father=father
def bianyi(self):#变异后不能把原来的个体改变,而是应该产生新个体
weizhi=random.randint(0,len(self.value)-1)
value=self.value.copy()
value[weizhi]=self.father.bianyi(weizhi)
return value
class qun:#种群类
def __init__(self,n:'数量',gs:'实例化的getis'):
self.pop=[geti(gs.born(),gs) for _ in range(n)]
def fanzhi(g1,g2):#之前的繁殖是挨着的dna才会交换,这里面是随机的选dna
g3,g4=geti(g1.value,g1.father),geti(g2.value,g2.father)
# 从列表中随机选择最多n-1个不同位置
lwz = random.sample(list(range(len(g1.value))),random.randint(1,len(g1.value)-1))
for wz in lwz:
g3.value[wz],g4.value[wz]=g4.value[wz],g3.value[wz]
return g3,g4
def sai(pop:'种群', k:'想保留的数量', tournsize:'锦标赛规模'):#锦标赛选拔
chosen = []
for i in range(k):
aspirants = random.sample(pop,tournsize)#参加比赛的个体
chosen.append(max(aspirants, key=lambda obj: obj.fit))#最强的入围
return chosen
def calfit(geti):#定义一下适应度函数,注意,这里面要调整成越大越好
value=geti.value
return 1/sum([(1.5-i)**2 for i in value])
def znh(pop):#中南海,选出最强一个
geti=max(pop, key=lambda obj: obj.fit)
return geti.value
def var(pop,pb:'变异概率',pf:'繁殖概率'):#繁殖+变异
nf=int(pf*len(pop))#繁殖次数
for _ in range(nf):
g1,g2=random.sample(pop,2)
g3,g4=fanzhi(g1,g2)
pop+=[g3,g4]
nb=int(pb*len(pop))#变异次数
for _ in range(nb):
g=random.choice(pop)
g2=geti(g.bianyi(),g.father)
pop.append(g2)
return pop
def fanyan(ngen:'繁衍的代数',pop:'种群',tournsize:'锦标赛规模',pb:'变异概率',pf:'繁殖概率'):#繁衍函数
k=len(pop)
for g in pop:#把适应度的算出来
if not g.fit:
g.fit=calfit(g)
for gen in range(ngen):
#完成交配+变异
pop = var(pop, pb, pf)
for g in pop:#把适应度的算出来
if not g.fit:
g.fit=calfit(g)
#选择过程,默认群体数量保持不变
pop = sai(pop,k,tournsize)
lv=[g.fit for g in pop]#适应值列表
lv.sort()
print(f'第{gen+1}代繁衍结束,平均适应度为{np.mean(lv)},适应度中位数为{lv[k//2]}')
return pop
# ================================================================
# 使用
# gs=getis([[[1,200],1],[[3,2,4,99,-50,1.5],2],[[1,20],1],[[1,22],1],[[11,22],1]])
# pop=qun(100,gs).pop
# pop=fanyan(200,pop,5,0.2,0.5)
# znh(pop)