[基因遗传算法]进阶之二:最优规划问题--多种编码方式+多变量

参考资料:
《遗传算法求解带约束优化问题(源码实现》
《有约束的遗传算法(Python代码实现)》
《遗传算法原理及其python实现》


同系列文章:
《[基因遗传算法]原理思想和python代码的结合理解之(一) :单变量》


解决的问题:线性规划最优解的问题. 可以应用在运筹学,优化问题, 最优传输理论的离散问题,深度学习中. 对于较简单的问题,应用广泛.
解决问题案例:
在这里插入图片描述

  • 目标函数:最小化. 如果求最大值,目标函数添加负号-
  • 不等式约束条件: 以小于号 ≤ \leq 为主.If ≥ \geq ,添加负号-,转化形态.
  • 自变量范围: 有两个自变量 x , y x,y x,y.分别具有自己的上下限,且好处是自变量的范围是连续的.

一、个体与种群

在这里插入图片描述

Fig.1 种群,个体,基因的关系

A. 个体的编码问题

在前一篇,我们采用了二进制编码的方式.其好处在于做交叉、变异的时候,代码写的非常舒服(便利).但同时其缺点明显.如果 x x x的定义域范围更广,要求精度更细.则其DNA的长度(存储单位)则会更长.因此对于个体编码有二进制编码、格雷编码、实数编码、符号编码。,具体可见:《万字字符长文带你了解遗传算法(有几个算例源码)》

不同的编码对应于不同的交叉和变异的代码书写思路.

B. 实数编码的交叉和变异的思路(单变量)

以上一篇的目标函数 y = 10 ⋅ s i n ( 5 x ) + 7 ⋅ c o s ( 4 x ) y=10 \cdot sin(5x)+7\cdot cos(4x) y=10sin(5x)+7cos(4x),定义域 x ∈ [ 0 , 5 ] x \in [0,5] x[0,5]为例.

NP=5
pop=np.random.uniform(0, 5,(NP,))# 实数编码
pop 

结果:
array([4.10882862, 4.50177413, 1.63557154, 3.38813064, 2.84975806])
交叉的某种方式: 节选父与母的一部分.

def crossover(parent1,parent2):
    if np.random.rand() < PC:    #交叉概率
        gamma=round(np.random.rand(),2)#随机产生一个(0,1)浮点数,并保留2位小数
        parent1=gamma*parent1+(1-gamma)*parent2
    return parent1

变异的某种方式:重新实数赋值

def mutation(child):
    # 用随机赋值的方式进行变异
    if np.random.rand() < PM:#变异概率
        child= np.random.uniform(0,5)#重新随机赋值
    return child

种群的交叉和变异:

pop_copy=pop.copy()
for i in range(NP):
    #parent1=pop[i]
    parent2=pop_copy[np.random.randint(NP)]# 随机产生父母2
    child=crossover(pop[i],parent2)#交叉
    pop[i]=mutation(child) #变异
pop 

结果:
array([3.63316795, 4.50177413, 1.63557154, 3.38813064, 3.78147027])

二、多变量的问题

以目标函数 Z = 2 a + x 2 − a c o s 2 π x + y 2 − a c o s 2 π y Z=2a+x^2-acos2πx+y^2-acos2πy Z=2a+x2acos2πx+y2acos2πy求最小值为例. x ∈ [ − 5 , 5 ] , y ∈ [ − 5 , 5 ] , a = 10 x \in [-5,5], y\in [-5,5],a=10 x[5,5],y[5,5],a=10.
当多变量的时候,相当于个体具有多条染色体,对应的染色体(表示相同特征,或说对应同一个自变量)之间才能交叉.

A.多变量的目标函数书写

def fitness_func(X):
    # 目标函数,即适应度值,X是种群的表现型
    a = 10
    pi = np.pi
    x = X[:, 0]
    y = X[:, 1]
    return 2 * a + x ** 2 - a * np.cos(2 * pi * x) + y ** 2 - a * np.cos(2 * 3.14 * y)

B. 二进制的编码的交叉和变异思路(多变量)

NP=5 #种群数量
DNA_SIZE=4#DNA长度,应设为20,为方便看结果缩小的
DNA_NUM=2#染色体个数
pop= np.random.randint(0, 2, (NP, DNA_SIZE*DNA_NUM))  
# 随机初始化种群,为50*40的0-1矩阵
pop 

结果:
在这里插入图片描述
解码方式

  • 对单条染色体解码
def decode(x, a, b):
    """解码,即基因型到表现型,同单变量相同"""
    xt = 0
    for i in range(len(x)):
        xt = xt + x[i] * np.power(2, i)
    return a + xt * (b - a) / (np.power(2, len(x)) - 1)
# 或者
def decode(x, a, b):
    """解码,即基因型到表现型"""
    DNA_SIZE=len(x)
    x_d=x.dot(2 ** np.arange(DNA_SIZE)[::-1]) *(b-a)/ float(2**DNA_SIZE-1) +a
    return x_d
  • 对个体(多条染色体)解码
def decode_X(pop: np.array,lb,ub):
    """
    对整个种群的基因解码,上面的decode是对某个染色体的某个变量进行解码
    pop:种群(二进制基因)
    lb: 变量的下限列表
    ub: 变量的上限列表
    """
    X =np.zeros((NP,n_dim))#解码后的种群的变量值存储,(5,2)
    indivi=np.zeros(n_dim)
    for i in range(NP):
        for j in range(n_dim):
            x =decode(pop[i,DNA_SIZE*j:DNA_SIZE*(j+1)],lb[j],ub[j])
            #xi = decode(pop[i, :20], -5, 5)
            indivi[j]=x
        
        X[i, :] = indivi
    return X

解码计算:

NP=5
DNA_SIZE=20#设为20
n_dim=2
pop= np.random.randint(0, 2, (NP, DNA_SIZE*n_dim)) 
lb=[-5,-5]
ub=[5,5]
X = decode_X(pop,lb,ub)
X

结果为:
array([[ 2.06021982, -0.35688911],
[ 2.00679494, -3.61610281],
[-4.44379753, -4.92298119],
[ 4.34191641, 4.12501252],
[-4.70489474, -0.42363684]])
(多变量)交叉与变异
与(单变量)二进制的交叉与变异类似,只是在外面多加了一套染色体个数的循环.

C.使用sko.GA解决问题

def aim(p):
    a = 10
    pi = np.pi
    x,y=p
    return 2 * a + x ** 2 - a * np.cos(2 * pi * x) + y ** 2 - a * np.cos(2 * 3.14 * y)
ga = GA(func=aim, n_dim=2, size_pop=50, max_iter=1000, 
lb=[-5,-5], ub=[5,5], precision=1e-7) 
best_result= ga.run()
print(best_result)

out:
(array([-9.94958624e-01, -3.72529039e-08]), array([0.99495906]))

总结思考: 通过这两篇的手写代码,可以充分理解基因遗传算法与代码结合的思想.
然而,我们与第三方库比较发现.第三方库sko.GA更好用.几行代码就解决了.因此,接下来思考,如何用sko.GA解决实际问题.

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于Python实现连续变量最优分箱详解,我可以为您提供一些基础的思路和代码实现。该方法是基于CART算法实现的,具体如下: 首先,我们需要导入相关的库,包括numpy、pandas和sklearn等: ```python import numpy as np import pandas as pd from sklearn.tree import DecisionTreeRegressor ``` 然后,我们需要定义一个函数来执行最优分箱操作,该函数的输入参数包括待分箱的数据、目标变量、最小样本数、最大分箱数、以及是否需要返回分箱结果等: ```python def binning_continuous_var(data, target, min_samples_leaf=50, max_bins=10, return_bins=False): # 将数据和目标变量拼接 data = pd.concat([data, target], axis=1) # 获取连续变量的列名 cont_cols = data.select_dtypes(include=[np.number]).columns.tolist() # 循环处理每个连续变量 for col in cont_cols: # 对该变量进行分箱操作 binned_col, bins = bin_continuous_var(data, col, target, min_samples_leaf, max_bins) # 将分箱结果更新到数据集中 data[col] = binned_col # 如果需要返回分箱结果,则返回数据集和分箱边界值 if return_bins: return data, bins # 否则,仅返回数据集 else: return data ``` 接下来,我们需要定义一个子函数来执行单个连续变量的分箱操作,该函数的输入参数包括待分箱的数据、连续变量的列名、目标变量、最小样本数和最大分箱数等: ```python def bin_continuous_var(data, col, target, min_samples_leaf, max_bins): # 获取该变量的取值范围 data_range = data[col].max() - data[col].min() # 如果取值范围为0,则直接返回原始变量和一个空的分箱边界值列表 if data_range == 0: return data[col], [] # 否则,使用CART算法进行分箱操作 else: # 初始化决策树模型 tree_model = DecisionTreeRegressor( criterion='mse', min_samples_leaf=min_samples_leaf, max_leaf_nodes=max_bins, random_state=42 ) # 拟合决策树模型 tree_model.fit(data[col].to_frame(), target) # 获取决策树的叶节点数目 n_leaves = tree_model.get_n_leaves() # 如果叶节点数目大于等于最大分箱数,则需要重新设置最大叶节点数目并重新拟合模型 while n_leaves >= max_bins: max_bins -= 1 tree_model = DecisionTreeRegressor( criterion='mse', min_samples_leaf=min_samples_leaf, max_leaf_nodes=max_bins, random_state=42 ) tree_model.fit(data[col].to_frame(), target) n_leaves = tree_model.get_n_leaves() # 获取叶节点的取值范围 leaves_range = [(tree_model.tree_.threshold[i - 1], tree_model.tree_.threshold[i]) for i in np.where(tree_model.tree_.children_left == -1)[0]] # 初始化分箱边界值列表,将最小值和最大值作为边界值的起点和终点 bins = [data[col].min()] + [i[1] for i in leaves_range[:-1]] + [data[col].max()] # 计算每个取值所对应的分箱编号 binned_col = np.digitize(data[col], bins) # 将分箱编号转换为分箱中心点的取值 binned_col = pd.Series(binned_col, index=data.index) binned_col = binned_col.map(lambda x: np.round(np.mean(data[target.name][binned_col == x]), 4)) # 返回分箱结果和分箱边界值列表 return binned_col, bins ``` 最后,我们可以使用上述代码实现对连续变量最优分箱操作,例如: ```python # 生成测试数据 data = pd.DataFrame({ 'col1': np.random.rand(1000), 'col2': np.random.rand(1000), 'col3': np.random.rand(1000), 'target': np.random.randint(0, 2, 1000) }) # 执行最优分箱操作 data_binned = binning_continuous_var(data.drop('target', axis=1), data['target'], min_samples_leaf=50, max_bins=10, return_bins=False) ``` 以上就是Python实现连续变量最优分箱的基础思路和代码实现,希望可以对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值