python实现遗传算法样例

一直想写一个遗传算法的样例,正好最近有空,写了一个。

 

遗传算法是一种无约束优化算法,借鉴了遗传理论,从一组初始点开始,计算目标函数,然后根据计算结果,对初始点进行交叉和变异操作,获得一组新的点。这一组新获得的点平均值优于初始点。如此往复迭代,直到达到所需要的精度为止。

 

遗传算法的步骤如下:

1. 令k=0,产生一个初始种群P(0)

2. 评估P(k),计算P(k)中每个个体的适应度

3. 如果满足停止规则,停止迭代

4. 从P(k)中选择新种群M(k)

5. 进化M(k),构成新种群P(k+1)

6. 令k=k+1,回到第2步

 

下面给出样例代码:

GenericAlgorithm.py

# -*- coding: utf-8 -*-

import numpy

# 遗传算法求最大值
class GenericAlgorithm:
    # func为要求最大值的函数
    # encoding决定是否对自变量进行编码
    # min为args对应最小值
    # max为args对应最大值
    # dnaLength为dna编码长度
    def __init__(self, func, min, max, encoding = False, dnaLength = 128):
        self._func = func
        self._min = min
        self._max = max
        self._flag = encoding
        self._dnaLen = dnaLength
    
    def __del__(self):
        return
        
    # 编码,仅在交叉和变异时使用,此处用最简单的二进制编码
    def _encode(self, matrix, length):
        rows = matrix.shape[0]
        columns = matrix.shape[1]
        realen = int(length / columns)
        bmax = 2**(realen) - 1
        r = [self._max[i] - self._min[i] for i in range(len(self._min))]
        mkb = []
        for i in range(rows):
            tmp = ''
            for j in range(columns):
                bstr = str(bin(int((matrix[i][j] - self._min[j])/r[j] * bmax)))
                bstr = bstr[2:].zfill(realen)
                tmp += bstr
            mkb.append(tmp)
        return mkb
        
    # 解码,同上
    def _decode(self, matrix, length):
        rows = len(matrix)
        columns = len(self._min)
        realen = int(length / columns)
        bmax = float(2**(realen) - 1)
        r = [self._max[i] - self._min[i] for i in range(len(self._min))]
        mk = numpy.zeros((rows, columns))
        for i in range(rows):
            for j in range(columns):
                tmp = matrix[i][j*realen:(j+1)*realen]
                mk[i][j] = int(tmp,2) / bmax * r[j] + self._min[j]
        return mk
        
    def _evolve(self, mk, prop_cross, prop_mut):
        mk = self._cross(mk, prop_cross)
        pk = self._mutation(mk, prop_mut)
        return pk
    
    # 交叉
    def _cross(self, mk, prop_cross):
        rows = mk.shape[0]
        columns = mk.shape[1]
        idx = numpy.zeros(1)
        while (idx.shape[0] % 2 != 0):
            idx = numpy.where(numpy.random.rand(rows,1) < prop_cross)[0]
        if (self._flag):
            mkb = self._encode(mk, self._dnaLen)
            for i in range(0, idx.shape[0], 2):
                bit = int(numpy.random.rand()*self._dnaLen)
                tmp1 = mkb[idx[i]][:bit] + mkb[idx[i+1]][bit:]
                tmp2 = mkb[idx[i+1]][:bit] + mkb[idx[i]][bit:]
                mkb[idx[i]] = tmp1
                mkb[idx[i+1]] = tmp2
            mk = mkb
        else:
            for i in range(0, idx.shape[0], 2):
                rn = numpy.random.rand()
                w = numpy.random.randn(1,columns)
                tmp1 = rn*mk[idx[i]] + (1-rn)*mk[idx[i+1]] + w
                tmp2 = (1-rn)*mk[idx[i]] + rn*mk[idx[i+1]] - w
                mk[idx[i]] = tmp1
                mk[idx[i+1]] = tmp2
            for i in range(rows):
                for j in range(columns):
                    mk[i][j] = numpy.clip(mk[i][j], self._min[j], self._max[j])
        return mk
    
    # 变异
    def _mutation(self, mk, prop_mut):
        if (self._flag):
            rows = len(mk)
            for i in range(rows):
                tmp = list(mk[i])
                idx = numpy.where(numpy.random.rand(self._dnaLen) < prop_mut)[0]
                for j in range(len(idx)):
                    if (tmp[idx[j]] == '0'):
                        tmp[idx[j]] = '1'
                    elif (tmp[idx[j]] == '1'):
                        tmp[idx[j]] = '0'
                    else:
                        print("just for extension.")
                mk[i] = ''.join(tmp)
            mk = self._decode(mk, self._dnaLen)
        else:
            rows = mk.shape[0]
            columns = mk.shape[1]
            idx = numpy.where(numpy.random.rand(rows,1) < prop_mut)[0]
            mk[idx] = mk[idx] + numpy.random.randn(idx.shape[0], columns)
            for i in range(rows):
                for j in range(columns):
                    mk[i][j] = numpy.clip(mk[i][j], self._min[j], self._max[j])
        return mk
    
    # 轮盘赌选择法
    def _select(self, values, pk):
        indexes = []
        min = numpy.min(values)
        values -= min    # 将values的值转换为正值,方便下面的操作
        summation = numpy.sum(values)
        population = values.shape[0]
        data = [(pk[i], values[i]) for i in range(population)]
        sorteddata = sorted(data, key = lambda ele: ele[1])
        for i in range(population):
            test = numpy.random.rand()
            sum = 0.0
            for j in range(population):
                sum += sorteddata[j][1]
                if (sum >= test*summation):
                    indexes.append(j)
                    break
        mk = numpy.zeros(pk.shape)
        for i in range(population):
            idx = indexes[i]
            mk[i] = sorteddata[idx][0]
        return mk
    
    # iterations:  最大迭代次数
    # population:  种群数量
    # prop_cross:  交叉概率
    # prop_mut:    变异概率
    def run(self, iterations, population, prop_cross, prop_mut):
        columns = len(self._min)
        p0 = numpy.random.randn(population, columns)  # 初始种群,每行为一组输入/一个个体
        r = [(self._max[i] - self._min[i])/2.0 for i in range(columns)]
        centerPoint = [self._min[i] + r[i] for i in range(columns)]
        for i in range(population):
            for j in range(columns):
                p0[i][j] = centerPoint[j] + p0[i][j]*r[j]
                p0[i][j] = numpy.clip(p0[i][j], self._min[j], self._max[j])
        values = numpy.zeros(population)
        pk = p0
        max = 0.0
        x_max = 0.0
        for iter in range(iterations):     # 开始迭代
            for i in range(population):
                values[i] = self._func(*pk[i])
            idx = numpy.argmax(values)
            x = pk[idx]
            y = values[idx]
            if (y > max):
                max = y
                x_max = x
            mk = self._select(values, pk)   # 选择mk
            pk = self._evolve(mk, prop_cross, prop_mut)  # 进化
        return (x_max, max)

代码中有注释,比较容易懂。但由于时间问题,部分代码仅实现了功能,没好好优化,导致无论代码格式还是算法本身,都比较丑。

 

接下来给出用法和测试代码:

test.py

# -*- coding: utf-8 -*-

import GenericAlgorithm as GA

def function(x, y):
    term1 = 3*numpy.power(1-x, 2)*numpy.exp(-numpy.power(x,2)-numpy.power(y+1,2))
    term2 = -10*(x/5 - numpy.power(x,3) - numpy.power(y,5))*numpy.exp(-numpy.power(x,2)-numpy.power(y,2))
    term3 = -numpy.exp(-numpy.power(x+1,2)-numpy.power(y,2))/3
    return term1 + term2 + term3
    
ga = GA.GenericAlgorithm(func=function, min=[-3,-3], max=[3,3], encoding=True, dnaLength=32)
(x, y) = ga.run(50, 20, 0.75, 0.0075)
print("GA: x = ", x, ", y = ", y)
xmax = (-0.0093, 1.5814)
ymax = function(xmax[0], xmax[1])
print("Real: x = ", xmax, ", y = ", ymax)

 

最终计算结果如下:

0d0ab5940d618e0177483f3a216d39387d8.jpg

转载于:https://my.oschina.net/propagator/blog/3068056

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
遗传算法(Genetic Algorithm)是一种基于进化论思想的优化算法,它通过模拟自然界的进化过程,不断地迭代、选择、交叉、变异来寻找最优解。 Python实现遗传算法的步骤: 1. 定义适应度函数(Fitness Function):适应度函数是遗传算法中最重要的部分,它用来评估个体的适应度,即个体的优良程度。适应度函数的设计必须符合问题的实际情况,并能够将问题转化为数学模型。 2. 初始化种群(Population):种群是由多个个体组成的集合。在遗传算法中,初始种群通常是随机生成的,每个个体由一组基因表示。基因可以是数字、字符、符号等,具体取决于问题的性质。 3. 选择操作(Selection):选择操作是为了从种群中选出优良的个体,使其参与繁殖下一代。选择操作有多种方法,如轮盘赌、竞标赛等。 4. 交叉操作(Crossover):交叉操作是将两个个体的基因进行配对,并随机地交换相应位置上的基因,产生新的个体。交叉操作可以保持种群多样性,促进优良基因的传递。 5. 变异操作(Mutation):变异操作是在个体的基因中随机改变某些位置上的值,以增加种群的多样性。变异概率通常很小,以避免过度的变化。 6. 繁殖下一代(Reproduction):通过选择、交叉、变异等操作,生成新的个体,并用新的个体替换掉原来的个体,构成新的种群。 7. 判断终止条件:当达到一定的迭代次数或找到满足要求的个体时,停止遗传算法的迭代过程。 下面是一个简单的Python程序,演示了如何实现遗传算法来求解函数的最小值。 ```python import random # 定义适应度函数 def fitness_function(x): return x ** 2 + 10 # 初始化种群 def init_population(size): population = [] for i in range(size): population.append(random.uniform(-10, 10)) return population # 选择操作 def selection(population, n): fitness = [fitness_function(x) for x in population] total_fitness = sum(fitness) probability = [f / total_fitness for f in fitness] selected = random.choices(population, probability, k=n) return selected # 交叉操作 def crossover(parents): a, b = parents return (a + b) / 2 # 变异操作 def mutation(child): r = random.uniform(-1, 1) return child + r # 遗传算法主程序 def genetic_algorithm(): population = init_population(20) for i in range(100): parents = selection(population, 2) child = crossover(parents) if random.random() < 0.1: child = mutation(child) population.remove(max(population, key=fitness_function)) population.append(child) return min(population, key=fitness_function) # 测试程序 if __name__ == '__main__': result = genetic_algorithm() print(result) ``` 在上面的程序中,适应度函数为$f(x)=x^2+10$,初始化种群大小为20,迭代次数为100,交叉概率为0.9,变异概率为0.1。程序最终输出的结果是最小值。 遗传算法是一种强大的优化算法,它可以用来解决许多实际问题。在实现遗传算法时,需要根据具体问题设计适应度函数、选择、交叉、变异等操作,以达到最优的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值