通过在每个索引处随机选择元素来合并N个列表

时间:2018-11-11 05:11:37

标签: python python-2.7 list random

我有成对的列表,每对大小相等。我想通过从每个索引中选择一个随机元素来“合并”每个对象,但是我当前的实现非常慢-在进行多处理时 even 。 (FWIW,我的代码确实需要可线程化的。)

def rand_merge(l1, l2):
    newl = []
    for i in range(len(l1)):
        q = random.choice([l1, l2])
        newl.append(q[i])
    return newl

非常基本,但是要在20k大小约为5-25的列表上运行,则要花很长时间-我认为它是随机的。但是我还尝试了其他版本的random,例如创建一个字符串0和1来引用,这是不行的。

编辑: 更清晰:这是一种遗传算法,旨在通过匹配语料库来编写句子。有问题的列表是按单词拆分的句子。遗传算法将获胜的健身“父母”“合并”到孩子中,每个孩子都是两个父句的“基因”的合并。 这意味着“列表”确实需要匹配,并且不能从更大的列表列表中提取(我不认为)。

这里有一些代码...

from multiprocessing import Pool as ThreadPool
import random

def offspring(parents):
    child = []
    p1 = parents[0].split(' ')
    p2 = parents[1].split(' ')
    for i in range(min(len(p1), len(p2))):
        q = random.choice([p1, p2])
        child.append(q[i])
    child = ' '.join([g for g in child]).strip()
    return child

def nextgen(l): #l is two lists of previous generation and grammar seed
    oldgen = l[0][:pop] # Population's worth of previous generation
    gramsent = l[1] # this is the grammar seed
    newgen = []
    newgen.append(tuple([oldgen[0][0], oldgen[0][0]]))  # Keep the winner!
    for i in range(len(oldgen) - len(oldgen)//4):
        ind1 = oldgen[0][0] # paired off against the winner - for larger pools, this is a random.sample/"tournament"
        ind2 = oldgen[i][0]
        newgen.append(tuple([ind1, ind2]))
    pool = ThreadPool(processes=8)
    newgen = pool.map(offspring, newgen)
    pool.close()
    pool.join()

人口和世代可以一起大量进入,并且每个句子都贯穿其中。自从最初发布问题以来,我就担心每一代人都需要花费很长时间才能解决问题,所以我发现(对于我来说,是头上的挠头)长的处理时间实际上(几乎)与“人口”规模或人数无关列表。变异每一代大约需要15秒。我将人口从50增加到50000,并将世代从15秒增加到17左右。因此,速度缓慢显然隐藏在其他地方。

1 个答案:

答案 0 :(得分:1)

尝试一次合并所有20,000个列表,而不是一次合并两个。

from itertools import zip_longest
from functools import partial
import random

lists = [l1, l2, ...]

idxvals = map(partial(filter, None), itertools.zip_longest(*lists))
newl = [random.choice([*i]) for i in idxvals]

由于要在每个索引中选择一个随机元素,因此一次选择所有20k列表而不是一次选择2个是有意义的。


>>> lists = [[1, 2, 3], [10], [20, 30, 40, 5]]

zip_longest将压缩到最长列表,并用None填充缺少的值。

>>> list(itertools.zip_longest(*lists))
[(1, 10, 20), (2, None, 30), (3, None, 40), (None, None, 5)]

这些“无”将需要在选择步骤之前过滤掉。 filter将对此有所帮助。

>>> f = partial(filter, None)
>>> list(map(list, map(f, itertools.zip_longest(*lists))))
[[1, 10, 20], [2, 30], [3, 40], [5]]

应该清楚我要做什么。输出的ith索引包含l[i]中每个l出现在lists上的那些元素。

现在,遍历idxvals并选择:

>>> idxvals = map(f, itertools.zip_longest(*lists))
>>> [random.choice([*i]) for i in idxvals]
[10, 30, 3, 5]