import math
import random
import numpy as np
import pandas as pd
class GA:
"""
遗传算法
"""
def __init__(self, train_rate=0.7, precision=4, min_=-10, max_=10, population=None):
self.train_rate = train_rate
self.precision = precision
self.min_ = min_
self.max_ = max_
self.population = population
@property
def __gene_length__(self):
"""
获取基因长度
"""
return int(math.log2((self.max_ - self.min_) * 10 ** self.precision)) + 1
def binary2float(self, n):
"""
二进制转为小数
"""
string_number1 = n if isinstance(n, str) else str(n)
decimal = 0
flag = False if '.' not in string_number1 else True
if flag:
string_integer, string_decimal = string_number1.split('.')
for i in range(len(string_decimal)):
decimal += 2 ** (-i - 1) * int(string_decimal[i])
number2 = int(str(int(string_integer, 2))) + decimal
return round(number2, self.precision)
else:
return int(string_number1, 2)
def float2binary(self, num):
"""
转化为二进制
"""
if num == int(num):
return '{:08b}'.format(int(num)) + '.' + '0' * self.precision
else:
integer = int(num)
flo = num - integer
integercom = '{:08b}'.format(integer)
tem = flo
tmpflo = []
for i in range(self.precision):
tem *= 2
tmpflo += str(int(tem))
tem -= int(tem)
return integercom + '.' + ''.join(tmpflo)
def chromosome(self):
"""
染色体
"""
return self.encode(self.population)
def encode(self, population):
"""
编码
"""
df_ = pd.DataFrame(np.array(population))
for row in range(df_.shape[0]):
df_.loc[row, :] = df_.loc[row, :].apply(lambda x: self.float2binary(x))
return df_
def decode(self, df_b):
"""
解码
"""
for row in range(df_b.shape[0]):
df_b.loc[row, :] = df_b.loc[row, :].apply(lambda x: self.binary2float(x))
return df_b
def gene_mutation(self, population, p=0.01):
"""
基因突变
"""
def temp_(n, p_):
s = [('0' if i == '1' else '1') if random.uniform(0.0, 1.0) <= p_ else i for i in n]
s.insert(-self.precision, '.')
return ''.join(s)
df_b = self.encode(population)
for row in range(df_b.shape[0]):
df_b.loc[row, :] = df_b.loc[row, :].apply(lambda x: x.replace('.', '')).apply(lambda x: temp_(n=x, p_=p))
return df_b
def fit_func(self, individual):
"""
适应度函数 这里用测试用 log2(n)
"""
return np.log2(individual[0])
def select(self, df_f, method='fit_func'):
"""
选择运算
"""
method = getattr(self, method, None)
if not method:
raise ValueError(f'{type(self).__name__} has no method: {method}')
population = df_f.to_numpy().tolist()
fit_ = [method(po) for po in population]
select_p = [round(i / sum(fit_), 17) for i in fit_]
accumulative_p = []
t_ = 0
for i in select_p:
t_ += i
accumulative_p.append(t_)
population_new = []
for i, p_ in enumerate(accumulative_p):
p_temp = random.uniform(0.0, 1.0)
if p_temp - 1 / np.PINF <= p_:
population_new.append(population[i])
else:
j = 0
while True:
if p_temp - 1 / np.PINF <= accumulative_p[j]:
population_new.append(population[j])
break
j += 1
df_f['fit'] = fit_
df_f['select_p'] = select_p
df_f['accumulative_p'] = accumulative_p
df_f['population_res'] = population_new
return population_new, df_f
def cross(self, df_b, p=0.6):
"""
交叉
"""
row, col = df_b.shape
pos = [r_ for r_ in range(len(df_b.loc[0, 0]))]
for c_ in range(col):
ls_ = [r_ for r_ in range(row)]
p_ = random.uniform(0.0, 1.0)
for rr_ in range(row//2):
if p_ <= p:
pos_ = random.choice(pos)
r1 = random.choice(ls_)
ls_.remove(r1)
r2 = random.choice(ls_)
ls_.remove(r2)
temp_ = df_b.loc[r1, c_]
df_b.loc[r1, c_] = temp_[:pos_] + df_b.loc[r2, c_][pos_:]
df_b.loc[r2, c_] = df_b.loc[r2, c_][:pos_] + temp_[pos_:]
return df_b
if __name__ == '__main__':
population = [random.randint(1, 10) for i in range(10)]
print(population)
ga = GA(population=population)
for i in range(1000):
df_b = ga.encode(population)
df_b = ga.cross(df_b, p=0.5)
df_f = ga.decode(df_b)
population, df_f = ga.select(df_f=df_f)
print(population)
print(df_f)
输出结果:
[5, 5, 9, 9, 7, 9, 8, 5, 5, 10]
[[10.0], [10.0], [10.0], [10.0], [10.0], [10.0], [10.0], [10.0], [10.0], [10.0]]
0 fit select_p accumulative_p population_res
0 10.0 3.321928 0.1 0.1 [10.0]
1 10.0 3.321928 0.1 0.2 [10.0]
2 10.0 3.321928 0.1 0.3 [10.0]
3 10.0 3.321928 0.1 0.4 [10.0]
4 10.0 3.321928 0.1 0.5 [10.0]
5 10.0 3.321928 0.1 0.6 [10.0]
6 10.0 3.321928 0.1 0.7 [10.0]
7 10.0 3.321928 0.1 0.8 [10.0]
8 10.0 3.321928 0.1 0.9 [10.0]
9 10.0 3.321928 0.1 1.0 [10.0]