You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遗传算法中子代数组修改引发父代数组变更的问题排查

遗传算法父代被意外修改问题排查与解决

算法流程与问题描述

我开发了一个从父代生成子代的遗传算法,流程如下:

  • 初始生成随机工作负载(由子数组构成的数组),参数:工作负载L=2、种群规模N=30、InputsNumber=3、突变率m=0.05
  • 对种群评分,选出得分最高的2个工作负载作为父代,此时新种群仅包含这两个父代
  • 通过交叉、突变函数从父代生成子代,将子代加入含父代的种群
  • 重复上述流程10次,每次从种群选最优2个作为父代

核心问题:调用mutation()函数修改子代值时,父代的值会同步变成子代的值——调用前父代数据正常,调用后父代数据被篡改。

父代/子代数组示例:[[0, 0, 0],[0, 0, 0]]
父代集合/子代集合数组示例:[ [[0, 0, 0],[0, 0, 0]], [[0, 0, 0],[0, 0, 0]] ]

原代码

import random

# 假设bcolors是已定义的颜色常量
bcolors = type('bcolors', (), {'OKGREEN': '\033[92m', 'ENDC': '\033[0m'})()

def generateRandomWorkload(inputsNumber, L, N):
    global population
    individualWorkload = []
    for n in range(N):
        for i in range(L):
            # 原代码此处可能存在问题:若inputsNumber是整数,len(inputsNumber)会报错
            individual = [0 for _ in range(len(inputsNumber))]
            individualWorkload.append(individual)

        population.append(individualWorkload)
        individualWorkload = []


def crossover(L):
    global parents, children

    children = []

    for i in range(2):
        C = random.randint(0, 1)
        R = random.randint(0, L)
        if C == 0:
            child = parents[0][0:R] + parents[1][R:L]
            children.append(child)
        elif C == 1:
            child = parents[1][0:R] + parents[0][R:L]
            children.append(child)

    return children


def mutation(mutation_rate):
    global children

    for i in range(len(children)):
        for j in range(len(children[i])):
            for k in range(len(children[i][j])):
                r = random.uniform(0, 1)
                if r <= mutation_rate:
                    children[i][j][k] = 1 - children[i][j][k]

    return children


def geneticAlgorithm(inputsNumber, L, N):
    global parents, children, population
    population = []
    generateRandomWorkload(inputsNumber, L, N)
    print("SEED POPULATION: ", population, "\n")

    for generation in range(10):
        print(bcolors.OKGREEN + "MEASUREMENTS OF ", generation+1, " GENERATION" + bcolors.ENDC)
        scoreI = []
        for individualWorkload in population:
            ### 此处计算评分(scoreI) ###
            # 示例:临时给个随机评分
            scoreI.append((individualWorkload, random.random()))

        # 父代选择
        print("PARENTS SELECTION...\n")
        scoreI.sort(key=lambda x: x[1])
        parents = [scoreI[-1][0], scoreI[-2][0]]
        population = [parents[0], parents[1]]
        print("SELECTED PARENTS:\n", parents, "\n")
        print("PARENTS IN POPULATION:", population)

        # 交叉
        print("BEGIN CROSSOVER...\n")
        print("PARENTS: ", parents)
        children = crossover(L)
        print("CROSSOVER CHILDREN:\n", children, "\n")

        # 突变
        print("BEGIN MUTATION...\n")
        print("PARENTS: ", parents)
        children = mutation(0.05)
        print("MUTATION CHILDREN:\n", children, "\n")

        # 新种群
        population.append(children[0])
        population.append(children[1])

        print("PARENTS: ", parents)
        print("NEW POPULATION:\n", population, "\n")

问题原因

问题根源是列表的浅拷贝:
在交叉函数中,child = parents[0][0:R] + parents[1][R:L]的切片操作仅对父代的外层列表做了拷贝,但内层的子数组(如[0,0,0])仍然和父代中的子数组指向同一个内存对象。当突变函数修改子代的子数组元素时,实际上是在修改父代的对应子数组元素。

解决方案

需要在交叉生成子代时,对嵌套的子数组做深拷贝,确保子代与父代的内存完全独立,有两种修改方式:

方式1:对子数组逐个浅拷贝(适用于单层嵌套)

修改交叉函数:

def crossover(L):
    global parents, children
    children = []
    for i in range(2):
        C = random.randint(0, 1)
        R = random.randint(0, L)
        if C == 0:
            # 对每个子数组单独拷贝,避免引用父代的子数组
            child = [sub.copy() for sub in parents[0][0:R]] + [sub.copy() for sub in parents[1][R:L]]
            children.append(child)
        elif C == 1:
            child = [sub.copy() for sub in parents[1][0:R]] + [sub.copy() for sub in parents[0][R:L]]
            children.append(child)
    return children

方式2:使用深拷贝(适用于多层嵌套)

导入copy模块后修改交叉函数:

import copy

def crossover(L):
    global parents, children
    children = []
    for i in range(2):
        C = random.randint(0, 1)
        R = random.randint(0, L)
        if C == 0:
            child = copy.deepcopy(parents[0][0:R]) + copy.deepcopy(parents[1][R:L])
            children.append(child)
        elif C == 1:
            child = copy.deepcopy(parents[1][0:R]) + copy.deepcopy(parents[0][R:L])
            children.append(child)
    return children

额外修复:生成随机工作负载的错误

原代码中generateRandomWorkload函数的len(inputsNumber)会报错(若inputsNumber是传入的整数3),应改为:

individual = [0 for _ in range(inputsNumber)]

内容的提问来源于stack exchange,提问作者serafm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:45:34