一.前言
在非线性函数寻优中,我们看到了编码方式对问题求解的重要性,但是遗传算法的评价函数的设定也对求解有至关重要的作用。如果设定的评价函数不好,可能导致算法无法正确收敛。
二.配词问题
1.问题描述
配词问题(word matching problem)是给定某字符串,以生成同样字符串为目的的问题。
例如对目标短语’to be or not to be’,要求用遗传算法生成该短语。
这里最简单直接的个体编码方式是采用13个ASCII码进行编码(当然用字符编码也是可以的,这里因为探讨的主要问题在于评价函数的选择,因此,不对编码方式做过多探索)。
考虑评价函数时,有两种评价思路:
- 第一种思路:是将目标函数设定为与给定的字符串的ASCII码差异,此时,配词问题转化为一个目标函数最小化问题。
- 第二种思路:是将目标函数设定与原文相同的字符个数,此时,配图问题转化为一个目标函数最大化问题。
2.评价方式一 - ASCII码差异
遗传算法操作:
- 个体编码:使用ASCII码数字编码,长度为13
- 评价函数:与给定的字符串的ASCII码差异的绝对值之和
- 育种选择:锦标赛选择
- 变异算法:交叉-均匀交叉,变异-乱序突变
- 环境选择:精英保留策略
代码实现
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author: liujie
@software: PyCharm
@file: ASCII差异.py
@time: 2020/11/28 19:36
"""
import numpy as np
import random
import matplotlib.pyplot as plt
from deap import creator,tools,base,algorithms
# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))
creator.create('Individual',list,fitness = creator.FitnessMin)
# 个体编码-ASCII编码
gen_size = 13
toolbox = base.Toolbox()
# 小写字母“a”到“z”的ASCII码值分别为97到到122
toolbox.register('genASCII',random.randint,97,122)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.genASCII,n = gen_size)
# 注册种群
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
# 评价函数-与给定的字符串的ASCII码差异之和
def eval(ind):
target = list('tobeornottobe')
# ord返回对应ASCII字符串的ASCII数值
target = [ord(item) for item in target]
return np.sum(np.abs(np.array(ind) - np.array(target))),
# 注册评价函数
toolbox.register('evaluate',eval)
# 注册遗传算法的操作:选择、交叉、突变
toolbox.register('select',tools.selTournament,tournsize = 2)
toolbox.register('mate',tools.cxUniform,indpb=0.5)
toolbox.register('mutate',tools.mutShuffleIndexes,indpb = 0.3)
# 创建统计学对象
stats = tools.Statistics(key= lambda ind : ind.fitness.values)
stats.register('avg',np.mean)
stats.register('std',np.std)
stats.register('min',np.min)
stats.register('max',np.max)
# 创建日志对象
logbook = tools.Logbook()
logbook.header = 'gen','avg','std','min','max'
# 遗传算法
pop_size = 100
N_GEN = 50
CXPB = 0.8
MUTPB = 0.2
# 生成种群
pop = toolbox.Population(n = pop_size)
# 评价初代种群
invalid_ind = [ind for ind in pop if not ind.fitness.valid]
fitnesses = list(map(toolbox.evaluate,invalid_ind))
for ind,fit in zip(pop,fitnesses):
ind.fitness.values = fit
record