这次代码的修改点在select函数中,在100个个体中,通过轮盘赌选择出前48个个体,然后再选择出最优个体和最差个体,总共50个,然后再在轮盘赌中后剩下的50个个体进行交叉和变异,返回出50个,这样50+50=100个体作为下一次进化的初始种群,如此不断循环,得出结果。
select如下:

def select(pop, fitness):  # nature selection wrt pop's fitness
    # fitnew=fitness.copy() #深拷贝
    fitnew = fitness
    # print('fitness',id(fitness))# 赋值操作在Python里是浅拷贝,两个变量地址一样
    # print('fitnew',id(fitnew))
    # print(id(fitnew)==id(fitness)) #True
    fitnew = fitnew + 1e-3 - np.min(fitnew)
    p = (fitnew) / (fitnew.sum())
    # print(np.arange(POP_SIZE))  #产生的是一维数组[0 1 2 ...100]
    # idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=p)
    # 从0~POP_SIZE这个序列里随机取样 如果[pop_size]是一维数组,就表示从这个一维数组中随机采样,采size个,上面这行是全采用
    idx = choicebyyang(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=p) #一维数组
    bestindex = getbest(pop, fitness) #最优个体下标
    worstindex=getworst(pop,fitness) #最差个体下标

    # new_idx=[bestindex,worstindex] #<class 'list'>: [0, 1]
    # new_idx=[idx]+[bestindex,worstindex] #<class 'list'>: [array([0, 0, 0]), 0, 2]
    # new_idx = list(idx) + [bestindex, worstindex] #<class 'list'>: [0, 1, 1, 1, 2]
    new_idx=list(idx) #<class 'list'>: [2, 1, 2]
    half_pop_idx=new_idx[:POP_SIZE//2-2]
    half_pop_idx.append(bestindex)
    half_pop_idx.append(worstindex)

    half_pop_idx2=new_idx[POP_SIZE//2:]


    return pop[half_pop_idx],pop[half_pop_idx2] # 尽量选择适应值高的函数值的个体

还有在循环主体有点变化如下:

for _ in range(N_GENERATIONS):  # 迭代N代
        x, y, z = translateDNA(pop)  # 这句代码,我觉得没啥作用
        # print(x) #(100,) [4.82264692 4.04610252 4.92107325 4.49556859 3.1322498  3.60757363...] 一维数组100个数据
        # pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
        # print(pop.dtype)#<class 'numpy.ndarray'> (100, 3) 2 300 float64
        fitness = get_fitness(pop)
        # print(fitness) #<class 'numpy.ndarray'> (100,) 一维数组 100
        pop_half,pop_half2 = select(pop, fitness)  # 选择生成新的种群 50行3列

        pop_half2=np.array(crossover_and_mutation(pop_half2, CROSSOVER_RATE)) #50行3列
        pop=np.vstack((pop_half,pop_half2)) #纵向拼接 1003列

完整代码如下:

# x1*x1-x1*x2+x3
import numpy as np
import random

DNA_SIZE = 1
POP_SIZE = 100
CROSSOVER_RATE = 0.8
MUTATION_RATE = 0.015
N_GENERATIONS = 200
X_BOUND = [3.0, 5.0]  # x1
Y_BOUND = [2.1, 6.7]  # x2
Z_BOUND = [1.2, 9.6]  # x3


sum=0#测试变量


def F(x, y, z):
    val = x * x - x * y + z
    # print(val.shape) #(100,) 100 <class 'numpy.ndarray'>
    return val


def get_fitness(pop):
    x, y, z = translateDNA(pop)
    pred = F(x, y, z)
    return pred


def translateDNA(pop):  # pop表示种群矩阵,一行表示一个二进制编码表示的DNA,矩阵的行数为种群数目
    # x_pop = pop[:,0:DNA_SIZE]#这样的写法shape 是(3, 1) 3行1列 ndim维度是2(行,列 矩阵 )
    # 也可以认为是二维数组,有3行,每行有1个元素 size为3 [[3.18796615]\n [3.32110516]\n [4.34665405]]
    '''因为这样写x_pop = pop[:, 0:DNA_SIZE] shape是(3,1)是二维数组,所以会报"对象太深,无法容纳所需的数组"的错误,
    第一种解决方法是进行reshape,比如reshape(3,)即变成了一维数组,元素个数是3个,即语法是x_pop=pop[:,0:DNA_SIZE].reshape(POP_SIZE,)
    这时x_pop就变为[4.96893731 3.24515899 3.51500566] 一维数组

    第二种方法是在矩阵(二维数组)pop中直接选择某一列元素,比如  pop[:, 0],表示选择pop第0列所有的元素

    '''

    x_pop = pop[:,0]  # 取前DNA_SIZE个列表示x 这样的写法shape是(3,) ndim维度是1 一维数组 ,数组元素有3个 size为3 [4.28040552 3.25412449 4.61336022]
    # print(x_pop.shape)
    y_pop = pop[:, 1]  # 取中间DNA_SIZE个列表示y
    z_pop = pop[:, 2]  # 取后DNA_SIZE个列表示z
    # print(x_pop)

    return x_pop, y_pop, z_pop


def mutation(child, MUTATION_RATE=0.003):
    if np.random.rand() < MUTATION_RATE:  # 以MUTATION_RATE的概率进行变异
        mutate_point = np.random.randint(0, DNA_SIZE * 3)  # 随机产生一个实数,代表要变异基因的位置
        if mutate_point == 0:
            child[mutate_point] = np.random.uniform(3.0, 5.0)
        elif mutate_point == 1:
            child[mutate_point] = np.random.uniform(2.1, 6.7)
        else:
            child[mutate_point] = np.random.uniform(1.2, 9.6)


def crossover_and_mutation(pop, CROSSOVER_RATE=0.015):
    new_pop = []
    for father in pop:  # 遍历种群中的每一个个体,将该个体作为父亲
        child = father  # 孩子先得到父亲的全部基因
        if np.random.rand() < CROSSOVER_RATE:  # 产生子代时不是必然发生交叉,而是以一定的概率发生交叉
            # mother = pop[np.random.randint(POP_SIZE)]  # 再种群中选择另一个个体,并将该个体作为母亲

            mother = pop[np.random.randint(POP_SIZE//2)]


            cross_points = np.random.randint(low=0, high=DNA_SIZE * 3)  # 随机产生交叉的点
            # child[cross_points:] = mother[cross_points:]  # 孩子得到位于交叉点后的母亲的基因
            child[cross_points] = mother[cross_points]
        mutation(child, MUTATION_RATE)  # mutation(child,MUTATION_RATE)每个后代有一定的机率发生变异
        new_pop.append(child)

    return new_pop


def getbest(pop, fitness):
    best_indiv = []
    fitness = get_fitness(pop)
    max_fitness_index = np.argmax(fitness)
    pop_copy_max = pop[max_fitness_index]
    best_indiv.append(pop_copy_max)
    # print(best_indiv)
    return max_fitness_index
def getworst(pop,fitness):
    worst_indiv = []
    fitness = get_fitness(pop)
    min_fitness_index = np.argmin(fitness)
    pop_copy_min = pop[min_fitness_index]
    worst_indiv.append(pop_copy_min)
    return min_fitness_index


def choicebyyang(arr, size, replace, p):
    for i in range(size):

        aa = np.random.rand()
        sum = 0
        for j in range(size):
            sum = sum + p[j]  # 累加概率
            if sum >= aa:
                break

        arr[i] = j
    return arr


def select(pop, fitness):  # nature selection wrt pop's fitness
    # fitnew=fitness.copy() #深拷贝
    fitnew = fitness
    # print('fitness',id(fitness))# 赋值操作在Python里是浅拷贝,两个变量地址一样
    # print('fitnew',id(fitnew))
    # print(id(fitnew)==id(fitness)) #True
    fitnew = fitnew + 1e-3 - np.min(fitnew)
    p = (fitnew) / (fitnew.sum())
    # print(np.arange(POP_SIZE))  #产生的是一维数组[0 1 2 ...100]
    # idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=p)
    # 从0~POP_SIZE这个序列里随机取样 如果[pop_size]是一维数组,就表示从这个一维数组中随机采样,采size个,上面这行是全采用
    idx = choicebyyang(np.arange(POP_SIZE), size=POP_SIZE, replace=True, p=p) #一维数组
    bestindex = getbest(pop, fitness) #最优个体下标
    worstindex=getworst(pop,fitness) #最差个体下标

    # new_idx=[bestindex,worstindex] #<class 'list'>: [0, 1]
    # new_idx=[idx]+[bestindex,worstindex] #<class 'list'>: [array([0, 0, 0]), 0, 2]
    # new_idx = list(idx) + [bestindex, worstindex] #<class 'list'>: [0, 1, 1, 1, 2]
    new_idx=list(idx) #<class 'list'>: [2, 1, 2]
    half_pop_idx=new_idx[:POP_SIZE//2-2]
    half_pop_idx.append(bestindex)
    half_pop_idx.append(worstindex)

    half_pop_idx2=new_idx[POP_SIZE//2:]


    return pop[half_pop_idx],pop[half_pop_idx2] # 尽量选择适应值高的函数值的个体


'''
如果POP_SIZE=3,即种群个数是3,则从交叉,变异后的种群中,选择3个适应值高 pop[idx]=[2 0 0]的新个体去
更新pop种群,之后再进行不断的迭代,直到达到迭代次数终止。
'''


def print_info(pop):
    fitness = get_fitness(pop)
    max_fitness_index = np.argmax(fitness)
    print("max_fitness:", fitness[max_fitness_index])
    x, y, z = translateDNA(pop)

    print("最优的基因型:", pop[max_fitness_index])

    print("(x, y, z):", (x[max_fitness_index], y[max_fitness_index], z[max_fitness_index]))


if __name__ == "__main__":
  # for i in range(100):#测试代码
    pop1 = np.random.uniform(3.0, 5.0, size=(POP_SIZE, DNA_SIZE))  # matrix (POP_SIZE, DNA_SIZE)
    pop2 = np.random.uniform(2.1, 6.7, size=(POP_SIZE, DNA_SIZE))
    pop3 = np.random.uniform(1.2, 9.6, size=(POP_SIZE, DNA_SIZE))

    # print(type(pop1))# (100,1) 维度是2(行列 矩阵) <class 'numpy.ndarray'>
    # pop={pop1,pop2,pop3}
    pop = np.hstack((pop1, pop2, pop3))#水平(左右)拼接
    # print(pop)
    '''
    [[3.44603448 4.51707625 7.90178727]
     [4.57616299 5.11309286 4.86911781]
     [3.24273815 2.9253602  4.45149325]
     ...
     [4.39321276 3.1657492  5.16654786]]
    '''
    # print(type(pop)) #<class 'numpy.ndarray'> n维数组
    # print(pop.shape) #(100,3) 矩阵有 100行,3列
    # print(pop.ndim) # 2 因为矩阵有行和列两个维度
    # print(pop.size) #300  矩阵共有300个元素
    # print(pop.dtype) #float64 矩阵元素类型是float64


    for _ in range(N_GENERATIONS):  # 迭代N代
        x, y, z = translateDNA(pop)  # 这句代码,我觉得没啥作用
        # print(x) #(100,) [4.82264692 4.04610252 4.92107325 4.49556859 3.1322498  3.60757363...] 一维数组100个数据
        # pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
        # print(pop.dtype)#<class 'numpy.ndarray'> (100, 3) 2 300 float64
        fitness = get_fitness(pop)

        # print(fitness) #<class 'numpy.ndarray'> (100,) 一维数组 100
        pop_half,pop_half2 = select(pop, fitness)  # 选择生成新的种群 50行3列

        pop_half2=np.array(crossover_and_mutation(pop_half2, CROSSOVER_RATE)) #50行3列
        pop=np.vstack((pop_half,pop_half2)) #纵向(上下)拼接 1003列



    print_info(pop)

    #测试 运行100次 的最大值平均值代码
#     i=i+1
#     print(i)
#     fitness = get_fitness(pop)
#     max_fitness_index = np.argmax(fitness)
#     sum=sum+fitness[max_fitness_index]
# print(sum/100.0)


'''#随机数-随机值
for i in range(10):
    i=np.random.rand()
    print(i)
    i=i+1
'''