遗传算法
本周搭建了python机器学习的相关环境,(机器学习相关包的下载建议用清华源 默认为外网)翻阅一些遗传算法博客,用自己的话简单总结了一下,并参考github一些分享,做了一个简单实验。下一步以论文思路进行思考,如何将遗传算法应用到内核参数配置推荐的场景当中。
一 算法流程及简单例子理解

查阅博客看到一个比较容易理解的例子,我给精简一下便于理解。
题目:求二元函数的最大值:

按照流程以此例逐一的分析:
(1) 个体编码
遗传算法的运算对象是表示个体的符号串,所以必须把变量 x1, x2 编码为一种符号串。本题中,用无符号二进制整数来表示。
例如:基因型 X=101110 所对应的表现型是:x=[ 5,6 ]。
(101 =5, 110 = 6)
(2) 初始群体的产生
遗传算法是对群体进行的进化操作,需要给其淮备一些表示起始搜索点的初始
群体数据。
本例群体规模的大小取为4,即群体由4个个体组成,假设选择四种不同的组合:011101,101011,011100,111001。
(3) 适应度汁算
遗传算法中以个体适应度的大小来评定各个个体的优劣程度,从而决定其遗传
机会的大小。
本例目标以求函数最大值为优化目标,故可直接利用目标函数值作为个体的适应度。
(4) 选择运算
选择运算(或称为复制运算)把当前群体中适应度较高的个体按某种规则或模型遗传到下一代群体中。一般要求适应度较高的个体将有更多的机会遗传到下一代群体中。
我总结为以下几步:
1 计算适应值,对应本例子的f(x)
2 计算适应度,也就是适应值/总和,就是占总数的百分比
3 最后再产生一个0到1之间的随机数,依据该随机数出现在上述哪一个概率区域内来确定各个个体被选中的次数。

5) 交叉运算
交叉运算是遗传算法中产生新个体的主要操作过程,它以某一概率相互交换某两个个体之间的部分染色体。
我总结为以下几步:
1 先对群体进行随机配对,其次随机设置交叉点位置
2 最后再相互交换配对染色体之间的部分基因,产生新的个体

(6) 变异运算
变异运算是对个体的某一个或某一些基因座上的基因值按某一较小的概率进行改变,它也是产生新个体的一种操作方法。
总结:
1 首先确定出各个个体的基因变异位置,随机产生的变异点位置
2 然后依照某一概率将变异点的原有基因值取反。

随着多轮的迭代,适应值会越来越大,越接近最优质,遗传算法感觉可以理解为参数搜素的一个过程,并利用了生物进化 优胜略汰的思想。
二 遗传算法基本代码框架
基本框架就按照算法流程写就行
class GA():
def __init__(self, nums, bound, func, DNA_SIZE=None, cross_rate=0.8, mutation=0.003):
pass
#将编码后的DNA翻译回来(解码)
def translateDNA(self):
pass
#得到适应度
def get_fitness(self, non_negative=False):
pass
#自然选择
def select(self):
pass
#染色体交叉
def crossover(self):
pass
#基因变异
def mutate(self):
pass
#进化
def evolution(self):
pass
#重置
def reset(self):
pass
#打印当前状态日志
def log(self):
pass
#一维变量作图
def plot_in_jupyter_1d(self, iter_time=200):
pass
三 简单实验
整体思想与上面简单例子一样,区别在于适应值的计算不同,目标不同。sklearn库已经附带了数据集,出于学习比较容易导入,该数据集包含了十三个特征,1代表选择,0代表不选择。

参数组合组成了数据集

该实例的适应值为计算线性回归估计的CV得分。 选择均方误差(MSE)作为度量:

该实例目标将得分接近于30,经过多轮迭代,得出结果很接近这个值。

跑之前得分:CV MSE before feature selection: 37.13
结果得分: CV MSE after feature selection: 28.92
实验代码:
import random
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
SEED = 2018
random.seed(SEED)
np.random.seed(SEED)
# ==============================================================================
# Data
# ==============================================================================
dataset = load_boston()
X, y = dataset.data, dataset.target
features = dataset.feature_names
# ==============================================================================
# CV MSE before feature selection
# ==============================================================================
est = LinearRegression()
score = -1.0 * cross_val_score(est, X, y, cv=5, scoring="neg_mean_squared_error")
print("CV MSE before feature selection: {:.2f}".format(np.mean(score)))
# ==============================================================================
# Class performing feature selection with genetic algorithm
# ==============================================================================
class GeneticSelector():
def __init__(self, estimator, n_gen, size, n_best, n_rand,
n_children, mutation_rate):
# Estimator
self.estimator = estimator
# Number of generations
self.n_gen = n_gen
# Number of chromosomes in population
self.size = size
# Number of best chromosomes to select
self.n_best = n_best
# Number of random chromosomes to select
self.n_rand = n_rand
# Number of children created during crossover
self.n_children = n_children
# Probablity of chromosome mutation
self.mutation_rate = mutation_rate
if int((self.n_best + self.n_rand) / 2) * self.n_children != self.size:
raise ValueError("The population size is not stable.")
def initilize(self):
population = []
for i in range(self.size):
chromosome = np.ones(self.n_features, dtype=np.bool)
mask = np.random.rand(len(chromosome)) < 0.3
chromosome[mask] = False
population.append(chromosome)
return population
def fitness(self, population):
X, y = self.dataset
scores = []
for chromosome in population:
score = -1.0 * np.mean(cross_val_score(self.estimator, X[:, chromosome], y,
cv=5,
scoring="neg_mean_squared_error"))
scores.append(score)
scores, population = np.array(scores), np.array(population)
inds = np.argsort(scores)
return list(scores[inds]), list(population[inds, :])
def select(self, population_sorted):
population_next = []
for i in range(self.n_best):
population_next.append(population_sorted[i])
for i in range(self.n_rand):
population_next.append(random.choice(population_sorted))
random.shuffle(population_next)
return population_next
def crossover(self, population):
population_next = []
for i in range(int(len(population) / 2)):
for j in range(self.n_children):
chromosome1, chromosome2 = population[i], population[len(population) - 1 - i]
child = chromosome1
mask = np.random.rand(len(child)) > 0.5
child[mask] = chromosome2[mask]
population_next.append(child)
return population_next
def mutate(self, population):
population_next = []
for i in range(len(population)):
chromosome = population[i]
if random.random() < self.mutation_rate:
mask = np.random.rand(len(chromosome)) < 0.05
chromosome[mask] = False
population_next.append(chromosome)
return population_next
def generate(self, population):
# Selection, crossover and mutation
scores_sorted, population_sorted = self.fitness(population)
population = self.select(population_sorted)
population = self.crossover(population)
population = self.mutate(population)
# History
self.chromosomes_best.append(population_sorted[0])
self.scores_best.append(scores_sorted[0])
self.scores_avg.append(np.mean(scores_sorted))
return population
def fit(self, X, y):
self.chromosomes_best = []
self.scores_best, self.scores_avg = [], []
self.dataset = X, y
self.n_features = X.shape[1]
population = self.initilize()
for i in range(self.n_gen):
population = self.generate(population)
return self
@property
def support_(self):
return self.chromosomes_best[-1]
def plot_scores(self):
plt.plot(self.scores_best, label='Best')
plt.plot(self.scores_avg, label='Average')
plt.legend()
plt.ylabel('Scores')
plt.xlabel('Generation')
plt.show()
sel = GeneticSelector(estimator=LinearRegression(),
n_gen=7, size=200, n_best=40, n_rand=40,
n_children=5, mutation_rate=0.05)
sel.fit(X, y)
sel.plot_scores()
score = -1.0 * cross_val_score(est, X[:, sel.support_], y, cv=5, scoring="neg_mean_squared_error")
print("CV MSE after feature selection: {:.2f}".format(np.mean(score)))
本文介绍了遗传算法的基本流程,包括个体编码、初始群体生成、适应度计算、选择运算、交叉运算和变异运算。通过一个求解二元函数最大值的简单例子,深入浅出地解释了每个步骤。此外,还给出了遗传算法的基本代码框架,并展示了使用遗传算法进行特征选择,以降低线性回归的均方误差的实验,最终实现了性能提升。
23万+

被折叠的 条评论
为什么被折叠?



