【python】机器学习 遗传算法

本文介绍了一种使用遗传算法进行解码的优化方法,通过随机生成DNA并应用交叉、变异操作,以找到自变量的最佳组合。算法利用适应度评估个体性能,通过多代迭代实现物竞天择的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单思路就是:

        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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值