遗传算法:
一种求最大值/最小值近似解的办法。与“梯度下降”、“模拟退火”类似。计算过程如下:
1)选择种群
选择100个左右的x值(即参数值)并进行编码,作为个体, 构成集合C。
2)计算适应度,并淘汰一部分个体。
这里涉及到适应度函数,和选择函数,由自己定义。
适应度函数:a = F( x ), 输入一个个体x,计算其适应度a,计算过程与所求最值有关。
选择函数:C’ = S( C ), 输入原集合,根据适应度决定保留的个体,得到新集合C’。
3)交叉变异
即进行编码互换和编码随机变异两个过程。
编码互换:个体间相互交换部分编码
编码随机变异:个体的编码随机发生变异。
以上两个过程都将产生新的个体,从而得到新种群: C’’ = P( C‘ )。
循环2)3)步骤,直到接近最值。
参考:超详细的遗传算法(Genetic Algorithm)解析
下面以计算函数 y = (x-4)^2在 [-10, 10)范围的最小值为例:
代码如下:
import numpy as np
import matplotlib.pyplot as plt
import time
p1 = 0.8 #交叉概率
p2 = 0.1 #变异概率
#评价和选择
def choose(C):
row, col = C.shape
individuals = []
for i in range(col):
individuals.append([C[:, i], (np.sum(C[:, i]) - 4 ) ** 2])
individuals.sort(key = lambda obj : obj[1])
#只保留25个个体
C = np.zeros((10, 25));
for i in range(25):
C[:, i] = individuals[i][0]
return C;
#交叉和变异
def produce(C):
row, col = C.shape
gen = []
for i in range(col):
p = np.random.rand()
if p <= p1:
index = int(np.random.rand() * 25) """随机选择一个个体"""
pos = int(np.random.rand() * 10) """随机选择一个交叉位置"""
new1 = C[:,i] + 0;
new2 = C[:, index] + 0;
temp = new1[pos]
new1[pos] = new2[pos];
new2[pos] = temp;
gen.append(new1);
gen.append(new2);
for i in range(col):
p = np.random.rand()
if p <= p2:
pos = int(np.random.rand() * 10); """随机选择一个变异位置"""
new1 = C[:, i] + 0;
new1[pos] = - new1[pos] + np.random.rand();
gen.append(new1)
#产生新种群
newC = np.zeros((10, col + len(gen)))
newC[:, 0:col] = C;
for i in range(len(gen)):
newC[:, i + col] = gen[i]
return newC;
#(1)产生并编码
# 这里产生100个x,每个x范围为[-10, 10)
# 将每个x编码成10个数, 即x = [x1, x2, ... , x10], 因此这里产生1000个随机数
X = (np.random.rand(1000) * 2 - 1).reshape(10, 100);
"""迭代30次"""
for i in range(30):
X = choose(X)
X = produce(X)
"""画图"""
sm = np.sum(X, axis = 0);
np.sort(sm)
plt.clf()
plt.xlim(0, 10)
plt.ylim(-1, 10)
plt.title("iter=" + str(i + 1) + ", avg = " + str(np.mean(sm)))
x = np.linspace(-10, 10, 100);
plt.plot(x, (x - 4)**2)
plt.scatter(sm, np.zeros((len(sm),)))
plt.pause(0.03)