首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python自定义列表构建优化

Python自定义列表构建优化
EN

Stack Overflow用户
提问于 2018-07-19 03:05:10
回答 2查看 100关注 0票数 1

我正在用Python编写一个遗传算法,然而,我的运算符(MMX)对于具有300万个权重的个体(每个个体是一个包含3.000.000个元素的列表)执行起来太长(10秒)。

下面是运算符的代码:

代码语言:javascript
复制
def calc_gen(maxel, minel, rec1, rec2, phiC):
    g = maxel - minel
    phi = 0
    if g > phiC:
        # Recta 2
        phi = rec2[0] * g + rec2[1]
    elif g < phiC:
        # Recta 1
        phi = rec1[0] * g + rec1[1]
    #Hay que asegurarse que no nos salimos del rango:
    maxv = min(1, maxel - phi)
    minv = max(0, minel + phi)
    gen1 = random.uniform(minv, maxv)  # Guardar el gen del primer hijo
    # Si C es el centro y A el elemento que ya tenemos y B el simétrico de A: C - A + C = B -> 2C - A = B
    # C = (maxv + minv) / 2; 2C - A = B -> maxv + minv - A = B
    # center = (maxv + minv) / 2
    gen2 = maxv + minv - gen1
    return gen1, gen2
    #return gen1, maxv + minv - gen1

def cxMMX(poblacion, rec1, rec2, phiC):
    start = timer()
    # Calcular el maximo y el minimo de cada gen en toda la población
    max_genes = numpy.amax(poblacion, axis=0).tolist()
    min_genes = numpy.amin(poblacion, axis=0).tolist()
    gis = timer()
    hijo1 = Individual()
    hijo2 = Individual()
    # Iterar dos listas a la vez (zip) con su indice (enumerate). Así crearemos los hijos simultáneamente en un loop
    for i, (maxel, minel) in enumerate(zip(max_genes, min_genes)):
        gen1, gen2 = calc_gen(maxel, minel, rec1, rec2, phiC)
        hijo1.append(gen1)
        hijo2.append(gen2)
    end = timer()
    #print("Tiempo Gi: %f Tiempo init: %f Tiempo calc gen: %f Tiempo mate total: %f" % (gis-start, init-gis, end-init, end-start))
    return [hijo1, hijo2]

rec1、rec2和phiC是决定如何进行交叉的参数,您不应该为它们操心。在整个算法中,它们具有相同的值。

poblacion是一个列表列表,假设它的形状是73000000。单个()是一个自定义类。它基本上继承了“列表”,并添加了一些属性来存储适应值。

分开做numpy.amax和numpy.amin看起来就像做了额外的工作。此外,可能还有一种更具pythonic风格的方法来执行"calc_gen()“循环。

PD:" gen1“依赖于" gen2 ":在一定范围内随机获取的gen1,然后通过寻找对称点来获得gen2。

PD2:关于MMX操作符的更详细的解释可以在original paper上找到,但是,您可以假设代码是正确的,并执行它必须做的事情。doi为https://doi.org/10.1007/3-540-44522-6_73

PD: enumerate()和I在旧代码中,忘记删除它们了!

编辑:使用Dillon Davis的解决方案减少了20%的时间。这是一个非常干净的解决方案,可以与任何自定义列表构建函数一起使用,前提是您通过执行一个函数获得列表的每个值:

代码语言:javascript
复制
def calc_gen_v2(maxel,minel, rec1m, rec1b, rec2m, rec2b, phiC):
    g = maxel - minel
    phi = 0
    if g > phiC:
        # Recta 2
        phi = rec2m * g + rec2b
    elif g < phiC:
        # Recta 1
        phi = rec1m * g + rec1b
    #Hay que asegurarse que no nos salimos del rango:
    maxv = min(1, maxel - phi)
    minv = max(0, minel + phi)
    gen1 = random.uniform(minv, maxv)  # Guardar el gen del primer hijo
    # Si C es el centro y A el elemento que ya tenemos y B el simétrico de A: C - A + C = B -> 2C - A = B
    # C = (maxv + minv) / 2; 2C - A = B -> maxv + minv - A = B
    # center = (maxv + minv) / 2
    gen2 = maxv + minv - gen1
    return gen1, gen2

def cxMMX_v3(poblacion, rec1, rec2, phiC):
    start = timer()
    # Calcular el maximo y el minimo de cada gen en toda la población
    max_genes = numpy.amax(poblacion, axis=0)
    min_genes = numpy.amin(poblacion, axis=0)
    gis = timer()
    hijo1, hijo2 = map(Individual, numpy.vectorize(calc_gen_v2)(max_genes, min_genes, rec1[0], rec1[1], rec2[0], rec2[1], phiC))
    end = timer()
    #print("Tiempo Gi: %f Tiempo init: %f Tiempo calc gen: %f Tiempo mate total: %f" % (gis-start, init-gis, end-init, end-start))
    return [hijo1, hijo2]

EDIT 2:Dillon Davis建议我用纯numpy实现它,将时间减少到3.5秒!(节省了65%的时间)

代码语言:javascript
复制
def cxMMX_numpy(poblacion, rec1, rec2, phiC):
    # Calculate max and min for every gen in the population
    max_genes = numpy.amax(poblacion, axis=0)
    min_genes = numpy.amin(poblacion, axis=0)
    g_pop = numpy.subtract(max_genes, min_genes)
    phi_pop = numpy.where(g_pop < phiC, numpy.multiply(g_pop, rec1[0]) + rec1[1], numpy.where(g_pop > phiC, numpy.multiply(g_pop, rec2[0]) + rec2[1], 0))
    maxv = numpy.minimum(numpy.subtract(max_genes, phi_pop), 1)
    minv = numpy.maximum(numpy.sum([min_genes, phi_pop], axis=0), 0)
    hijo1 = numpy.random.uniform(low=minv, high=maxv, size=minv.size)
    hijo2 = numpy.subtract(numpy.sum([maxv, minv], axis=0), hijo1)
    return [Individual(hijo1), Individual(hijo2)]

注意:如果您想要重用,则单个继承自列表

注意:如果g=phiC,那么rec1 * g_pop + rec11=0,always,rec1和rec11保证了这一点!因此,也许做数学计算比三重选择更好?

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51409330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档