【机器学习】多目标遗传算法+模拟退火算法
【python】机器学习 多目标遗传算法
import numpy as np
# --------------------------------------------
# 参数设置
# --------------------------------------------
DNA_SIZE = 5 # DNA长度
POP_SIZE = 50 # 初始种群数
CROSSOVER_RATE = 0.95 # 交叉概率
MUTATION_RATE = 0.01 # 变异概率
N_GENERATIONS = 100 # 迭代次数
# --------------------------------------------
SAMPLE_SIZE = 123 # 样本数
x1_BOUND = [100000, 1000000]
x2_BOUND = [0.04, 15]
class SAMPLE(): # 单次样本结构--------------------------------------------
def __init__(self):
self.sample = []
self.decode_data = []
self.num = SAMPLE_SIZE
def pop_make(self, dna):
for i in range(len(dna)):
self.sample.append([])
for i in range(len(dna)): # i:种群数
for j in range(self.num): # j:每个种群内的个体数
self.sample[i].append(dna[i][j::self.num])
def decode(self, bound):
for i in self.sample:
a_sample = []
for j in i:
a_price = np.dot(j, 2 ** np.arange(DNA_SIZE)[::-1]) / float(2 ** DNA_SIZE - 1) * (bound[1] - bound[0]) + \
bound[0]
a_sample.append(a_price)
self.decode_data.append(a_sample)
class GA(): # 遗传算法--------------------------------------------
def __init__(self):
# 每次迭代中最好的数据
self.fitness = []
self.y1 = []
self.y2 = []
self.y3 = []
self.x1 = []
self.x2 = []
# 解码过程 ----------------------------------------------------------------------------------------
def translateDNA(self, DNA, bound):
sample = SAMPLE()
sample.pop_make(DNA)
sample.decode(bound)
return sample.decode_data
# 交叉变异 ----------------------------------------------------------------------------------------
def crossover_and_mutation(self, DNA, CROSSOVER_RATE=CROSSOVER_RATE):
new_DNA = []
for father in DNA:
child = father
if np.random.rand() < CROSSOVER_RATE:
mother = DNA[np.random.randint(POP_SIZE)]
cross_points = np.random.randint(low=0, high=DNA_SIZE * SAMPLE_SIZE)
child[cross_points:] = mother[cross_points:]
if np.random.rand() < MUTATION_RATE:
mutate_point = np.random.randint(0, DNA_SIZE * SAMPLE_SIZE)
child[mutate_point] = child[mutate_point] ^ 1
new_DNA.append(child)
return new_DNA
# 计算适应值 --------------------------------------------------------------------------------------
def get_fitness(self, DNA1, DNA2):
"""
对DNA解码-->x
x-->y
y-->fitness
show函数:
记录最大的fitness值,便于画图
记录x和y,便于添加到附件
"""
x1 = self.translateDNA(DNA1, x1_BOUND)
x2 = self.translateDNA(DNA2, x2_BOUND)
y1 = []
y2 = []
fitness = []
self.show(fitness, x1, x2, y1, y2, y3)
return fitness, y1, y2, y3
# 选择适应值高的个体 ------------------------------------------------------------------------------
def select(self, DNA, DNA2, fitness):
fitness = fitness - np.min(fitness) + 1e-3
idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=fitness / fitness.sum())
return DNA[idx], DNA2[idx]
# 每次迭代的信息print --------------------------------------------
def show(self, fitness, x1, x2, y1, y2, y3):
"""
记录最大的fitness到self中,便于画图(fitness[index])
将对应的x和y也记录到self中,便于储存到本地(x[index],y[index])
"""
max_fitness = max(fitness)
index = fitness.index(max_fitness)
self.fitness.append(max_fitness)
self.y1.append(y1[index])
self.y2.append(y2[index])
self.y3.append(y3[index])
self.x1.append(x1[index])
self.x2.append(x2[index])
print("银行收益:{:.4f}".format(y1[index]))
print("流失率总和:{:.4f}".format(y3[index]))
# 每次迭代记录 ---------------------------------------------------
def load(self):
path_1 = r"……"
path_2 = r"……"
header = ["……", "……"]
write_excel(self.x1, path_1)
write_excel(self.x2, path_2)
# 30次迭代画图 --------------------------------------------
def draw(self):
y1_name = "y1"
y2_name = "y2"
save_path = r"C:\Users\Administrator\Desktop\a.png"
import matplotlib.pyplot as plt
x = range(1, N_GENERATIONS + 1)
fig = plt.figure(figsize=(20, 10))
plt.style.use('seaborn-whitegrid')
ax1 = fig.add_subplot(311)
plt.legend(fontsize=20)
ax1.plot(x, self.fitness, linestyle=':', linewidth=1, marker='d', markersize=5, label="适应度")
plt.ylabel("适应度", fontsize=20)
ax2 = fig.add_subplot(211)
ax2.plot(x, self.y1, linestyle='-.', linewidth=1, marker='+', markersize=5, label=y1_name)
plt.ylabel(y1_name, fontsize=20)
plt.legend(fontsize=20)
ax2 = fig.add_subplot(212)
ax2.plot(x, self.y3, linestyle='-.', linewidth=1, marker='^', markersize=5, label=y2_name)
plt.xlabel("迭代次数", fontsize=20)
plt.ylabel(y2_name, fontsize=20)
plt.legend(fontsize=20)
plt.savefig(save_path, bbox_inches='tight', dpi=1000)
plt.show()
if __name__ == "__main__":
DNA1 = np.random.randint(2, size=(POP_SIZE, DNA_SIZE * SAMPLE_SIZE))
DNA2 = np.random.randint(2, size=(POP_SIZE, DNA_SIZE * SAMPLE_SIZE))
ga = GA()
for i in range(N_GENERATIONS):
print("迭代第%d次-------------------------------------------- " % (i + 1))
DNA1 = np.array(ga.crossover_and_mutation(DNA1, CROSSOVER_RATE))
DNA2 = np.array(ga.crossover_and_mutation(DNA2, CROSSOVER_RATE))
fitness, y1, y2, y3 = ga.get_fitness(DNA1, DNA2)
DNA1, DNA2 = ga.select(DNA1, DNA2, fitness)
ga.draw()
ga.load()
【python】机器学习 遗传算法
简单思路就是:
DNA = np.random.randint(2, size=(POP_SIZE, DNA_SIZE * NUM))
for i in range(N_GENERATIONS):
将DNA分为NUM个矩阵,矩阵的每一行翻译为一个数字
DNA变异交叉
计算适应度
物竞天择
代码:
"""
--------------------------------------------
DNA_SIZE: DNA长度,长度越长精度越高
POP_SIZE: 初始种群数
CROSSOVER_RATE: 交叉概率
MUTATION_RATE: 变异概率
N_GENERATIONS: 迭代次数
X1_BOUND: x1自变量范围
X2_BOUND: x2自变量范围
NUM: 自变量数量
--------------------------------------------
"""
import numpy as np
# 初始化群体----------------------------------------------------------------------------------------
DNA_SIZE = 5 # DNA长度,x1,x2各5个,长度越长精度越高
POP_SIZE = 50 # 初始种群数
CROSSOVER_RATE = 0.95 # 交叉概率
MUTATION_RATE = 0.01 # 变异概率
N_GENERATIONS = 30 # 迭代次数
X1_BOUND = [-1, 2] # x1自变量范围
X2_BOUND = [-1, 2] # x2自变量范围
# 定义函数----------------------------------------------------------------------------------------
def function(x1, x2):
# y = f(x1,x2)
return y
class GA():
# 解码过程 ----------------------------------------------------------------------------------------
def translateDNA(self, DNA):
# DNA表示种群矩阵,一行表示一个二进制编码表示的DNA,矩阵的行数为种群数目
x1_DNA = DNA[:, 1::2] # 前DNA_SIZE位表示x1 (1::2:从下标1开始,步长2)
x2_DNA = DNA[:, ::2] # 后DNA_SIZE位表示x2
# DNA:(POP_SIZE,DNA_SIZE)*(DNA_SIZE,1) --> (POP_SIZE,1)
# # 转二进制 --> 除2的SIZE次方 --> 摆开到bound间
x1 = x1_DNA.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2 ** DNA_SIZE - 1) * (X1_BOUND[1] - X1_BOUND[0]) + \
X1_BOUND[0]
x2 = x2_DNA.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2 ** DNA_SIZE - 1) * (X2_BOUND[1] - X2_BOUND[0]) + \
X2_BOUND[0]
return x1, x2
# 交叉过程 ----------------------------------------------------------------------------------------
def crossover_and_mutation(self, DNA, CROSSOVER_RATE=CROSSOVER_RATE):
new_DNA = []
for father in DNA: # 遍历种群中的每一个个体,将该个体作为父亲
child = father # 孩子先得到父亲的全部基因(这里我把一串二进制串的那些0,1称为基因)
if np.random.rand() < CROSSOVER_RATE: # 产生子代时不是必然发生交叉,而是以一定的概率发生交叉
mother = DNA[np.random.randint(POP_SIZE)] # 再种群中选择另一个个体,并将该个体作为母亲
cross_points = np.random.randint(low=0, high=DNA_SIZE * 2) # 随机产生交叉的点
child[cross_points:] = mother[cross_points:] # 孩子得到位于交叉点后的母亲的基因
self.mutation(child) # 每个后代有一定的机率发生变异
new_DNA.append(child)
return new_DNA
# 变异过程 ----------------------------------------------------------------------------------------
def mutation(self, child, MUTATION_RATE=MUTATION_RATE):
if np.random.rand() < MUTATION_RATE: # 以MUTATION_RATE的概率进行变异
mutate_point = np.random.randint(0, DNA_SIZE * 2) # 随机产生一个实数,代表要变异基因的位置
child[mutate_point] = child[mutate_point] ^ 1 # 将变异点的二进制为反转
# 计算适应值 ----------------------------------------------------------------------------------------
def get_fitness(self, DNA):
x1, x2 = self.translateDNA(DNA)
pred = function(x1, x2)
return (pred - np.min(pred)) + 1e-3
'''
减去最小的适应度是为了防止适应度出现负数,
通过这一步fitness的范围为[0, np.max(pred)-np.min(pred)],
最后在加上一个很小的数防止出现为0的适应度
'''
# 选择适应值高的个体 ----------------------------------------------------------------------------------------
def select(self, DNA, fitness): # nature selection wrt DNA's fitness
idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=fitness / fitness.sum())
return DNA[idx]
if __name__ == "__main__":
DNA = np.random.randint(2, size=(POP_SIZE, DNA_SIZE * 2))
ga = GA()
for i in range(N_GENERATIONS):
x1, x2 = ga.translateDNA(DNA)
DNA = np.array(ga.crossover_and_mutation(DNA, CROSSOVER_RATE))
fitness = ga.get_fitness(DNA)
DNA = ga.select(DNA, fitness)
【python】机器学习 模拟退火算法
简单的思路是:
T = T0
while T > Tf:
random随机产生iter个x,即X=[x0,x1,x2,x3,...]
循环iter次:
对于xi,求fi
基于xi,产生新值x'
x'=x+T*(random()-random())
M-H判断是否接受新值
计算f(x'),如果f(x')比fi更符合条件,接受
否则:
random()<exp(△f/T),接受
否则:拒绝
基于此时的X,计算F=[f0,f1,f2,f3,……]
取最符合条件的f_best
T = T * alpha
代码:
"""
--------------------------------------------
x: 所求变量
f: f(x)为目标函数
iter: 内循环值
T0: 初始温度
Tf: 终止温度
alpha: 降温系数
--------------------------------------------
"""
import math
from random import random
def Function(x, y):
res = 4 * x ** 2 - 2.1 * x ** 4 + x ** 6 / 3 + x * y - 4 * y ** 2 + 4 * y ** 4
return res
class SA:
def __init__(self, iter=100, T0=100, Tf=0.01, alpha=0.99):
self.iter = iter # 内循环迭代次数,即为L =100
self.alpha = alpha # 降温系数,alpha=0.99
self.T0 = T0 # 初始温度T0为100
self.Tf = Tf # 温度终值Tf为0.01
self.T = T0 # 当前温度
self.x = [random() * 11 - 5 for i in range(iter)] # 随机生成100个x的值
self.y = [random() * 11 - 5 for i in range(iter)] # 随机生成100个y的值
self.most_best = []
# 扰动产生新解的过程----------------------------------------------------------------------------------------
def generate_new(self, x, y):
while True:
x_new = x + self.T * (random() - random())
y_new = y + self.T * (random() - random())
if (-5 <= x_new <= 5) & (-5 <= y_new <= 5):
break # 重复得到新解,直到产生的新解满足约束条件
return x_new, y_new
# Metropolis准则----------------------------------------------------------------------------------------
def Metrospolis(self, f, f_new):
if f_new <= f:
return 1
else:
p = math.exp((f - f_new) / self.T)
if random() < p:
return 1
else:
return 0
# 获取最优目标函数值----------------------------------------------------------------------------------------
def best(self):
f_list = [] # f_list数组保存每次迭代之后的值
for i in range(self.iter):
f = Function(self.x[i], self.y[i])
f_list.append(f)
f_best = min(f_list)
idx = f_list.index(f_best)
return f_best, idx # f_best,idx分别为在该温度下,迭代L次之后目标函数的最优解和最优解的下标
# 主函数----------------------------------------------------------------------------------------
def run(self):
while self.T > self.Tf:
for i in range(self.iter):
f = Function(self.x[i], self.y[i]) # f为迭代一次后的值
x_new, y_new = self.generate_new(self.x[i], self.y[i]) # 产生新解
f_new = Function(x_new, y_new) # 产生新值
if self.Metrospolis(f, f_new): # 判断是否接受新值
self.x[i] = x_new # 如果接受新值,则把新值的x,y存入x数组和y数组
self.y[i] = y_new
# 迭代L次记录在该温度下最优解
ft, _ = self.best()
# 温度按照一定的比例下降(冷却)
self.T = self.T * self.alpha
# 得到最优解
f_best, idx = self.best()
print(f"F={f_best}, x={self.x[idx]}, y={self.y[idx]}")
if __name__ == "__main__":
SA().run()

浙公网安备 33010602011771号