import matplotlib.pyplot as plt
import numpy as np
import random
import pandas as pd
遗传算法求函数最值
遗传算法的特点有无须可导,可优化离散异构数据。
参考:
- 遗传算法python实现
- 科学前沿:Genetic Algorithm - 遗传算法究竟怎么回事
问题定义
如下图所示,
在区间
[-1, 2]
上有很多极大值和极小值,如果要求其最大值或最小值,很多单点优化的方法(梯度下降等)就不适合,这种情况下就可以用遗传算法(Genetic Algorithm)。
def fun(x):
return x * np.sin(10*np.pi*x) + 2
Xs = np.linspace(-1, 2, 100)
plt.plot(Xs, fun(Xs))
初始化原始种群
遗传算法的一个特点是同时优化一批解(种群),例如下面在[-1, 2]
范围内随机生成
个点:
np.random.seed(0)
# 初始化原始种群
def ori_popular(num, _min=-1, _max=2):
return np.random.uniform(_min, _max, num) # 范围[-1, 2)
#__TEST__
population = ori_popular(10)
for pop, fit in zip(population, fun(population)):
print("x=%5.2f, fit=%.2f"%(pop, fit))
plt.plot(Xs, fun(Xs))
plt.plot(population, fun(population), '*')
plt.show()
>>>
x= 0.65, fit=2.64
x= 1.15, fit=0.87
x= 0.81, fit=2.21
x= 0.63, fit=2.56
x= 0.27, fit=2.21
x= 0.94, fit=1.13
x= 0.31, fit=1.88
x= 1.68, fit=3.17
x= 1.89, fit=2.53
x= 0.15, fit=1.85
上图显示我们随机选的
个点离最大值(3.8左右)差距还挺远,下面用GA算法看能否求到最优解。
编码
编码,也就是由表现型到基因型,性征到染色体。
二进制编码的缺点:对于一些连续函数的优化问题,由于其随机性使得其局部搜索能力较差,如对于一些高精度的问题,当解迫近于最优解后,由于其变异后表现型变化很大,不连续,所以会远离最优解,达不到稳定。而格雷码能有效地防止这类现象。
TODO:
- [ ] 用
2**18
扩展似乎会损失精度,准备用10000
代替
下面分别将1, 10, 0
转成二进制编码,注意浮点数0.1
无法转换:
print("1:", bin(1))
print("10:", bin(10))
print("0:", bin(0))
try:
print("0.1:", bin(0.1))
except Exception as E:
print("Exception: {}".format(type(E).__name__), E)
>>>
1: 0b1
10: 0b1010
0: 0b0
Exception: TypeError 'float' object cannot be interpreted as an integer
为了能编码浮点数,需要扩大倍数转成整数:
X = [1, 0.1, 0.002]
print("2**18 =", 2**18, 'n')
for x in X:
tx = int(x * 2**18)
print("%.4f => %6d => %s"%(x, tx, bin(tx)))
2**18 = 262144
>>>
1.0000 => 262144 => 0b1000000000000000000
0.1000 => 26214 => 0b110011001100110
0.0020 => 524 => 0b1000001100
for x in X:
tx = int(x * 2**18)
ex = bin(tx)
dx = int(ex, 2) / 2**18
print("%25s => %6d => %.4f"%(ex, tx, dx))
>>>
0b1000