使用 for 循环的结果在 python 中创建新列表

Use result of forloop to create new list in python

我创建了一个 mutate_v1 函数,可以在 DNA 序列中生成随机突变。

def mutate_v1(sequence, mutation_rate):
    dna_list = list(sequence)
    for i in range(len(sequence)):
        r = random.random()
        if r < mutation_rate:
            mutation_site = random.randint(0, len(dna_list) - 1)
            dna_list[mutation_site] = random.choice(list('ATCG'))
        return ''.join(dna_list)

如果我将函数应用于 G0 的所有元素,我会得到新一代 (G1) 突变体(突变序列列表) .

G0 = ['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']

G1 = [mutate_v1(s,0.01) for s in G0]

#G1
['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']

如何将我的功能重复到 G20(20 代)?

我可以像下面这样手动完成

G1   = [mutate_v1(s,0.01) for s in G0]
G2   = [mutate_v1(s,0.01) for s in G1]
G3   = [mutate_v1(s,0.01) for s in G2]
G4   = [mutate_v1(s,0.01) for s in G3]
G5   = [mutate_v1(s,0.01) for s in G4]
G6   = [mutate_v1(s,0.01) for s in G5]
G7   = [mutate_v1(s,0.01) for s in G6]

但我确信 for 循环会更好。 我已经测试了几个 codes 但没有结果。

有人可以帮忙吗?

使用range迭代到代数,并将每一代存储在一个列表中,每一代都是变异前一代的结果:

G0 = ['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']

generations = [G0]
for _ in range(20):
    previous_generation = generations[-1]
    generations.append([mutate_v1(s, 0.01) for s in previous_generation])

# then you can access by index to a generation
print(generations[1])  # access generation 1
print(generations[20]) # access generation 20

输出

['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']
['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAT']

Dani 的回答是一个很好的简单解决方案,但我想在 Python、 生成器函数中使用稍微更高级的编程技术来演示另一种方法:

def mutation_generator(g0):
    g = g0.copy()
    while True:
        yield g
        g = [mutate_v1(seq, 0.01) for seq in g]

现在,mutation_generator 是一个无限序列生成器,这意味着您理论上可以无限期地继续发展您的序列。如果要抢20代:

g0 = ['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']
generation = mutation_generator(g0)
twenty_generations = [next(generation) for _ in range(20)]

这个生成器的好处是我们可以在任何时候从它停止的地方重新启动它。假设您已经对前 20 代进行了一些分析,现在您想了解接下来的 100 代会发生什么:

next_hundred = [next(generation) for _ in range(100)]

现在,我们可以初始化一个 new 生成器,使用 twenty_generations 的最后一代作为新生成器的初始生成,但这不是必需的,因为我们的 generation 生成器在第 20 代时就停止了,并且随时准备在您调用 next(generation).

时继续变异

这开辟了很多可能性,包括发送新的变异率参数,或者如果您愿意,甚至可以发送全新的变异函数。真的,随便你。

这里的另一个好处是您可以 运行 在同一个初始序列上使用多个生成器并观察它们是如何发散的。请注意,使用在函数中使用 for 循环的更传统方法完全可以做到这一点,但使用生成器的好处是您不必一次生成整个序列;它只会在您告诉它时发生变异(通过 next())。例如:

g0 = ['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']
universe_1 = mutation_generator(g0)
universe_2 = mutation_generator(g0)
universe_3 = mutation_generator(g0)

# The first generation is always the same as g0, but this can be modified if you desire
next(universe_1)
next(universe_2)
next(universe_3)

# Compare the first mutation without having to calculate twenty generations in each 'universe' before getting back results
first_mutation_u1 = next(universe_1)
first_mutation_u2 = next(universe_2)
first_mutation_u3 = next(universe_3)

同样,您还可以修改生成器函数mutation_generator以接受其他参数,例如自定义变异函数,甚至可以随时更改变异率等

最后,作为旁注,使用生成器可以很容易地跳过数千代,而无需在内存中存储多个序列:

g0 = ['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']
generation = mutation_generator(g0)
for _ in range(10000):
    next(generation)

print(g0)  # first gen
print(next(generation))  # ten thousand generations later

输出:

['CTGAA', 'CTGAA', 'CTGAA', 'CTGAA', 'CTGAA']
['TTGGA', 'CTTCG', 'TGTGA', 'TAACA', 'CATCG']

使用 for 基于循环的方法,您将不得不创建并存储所有 10000 代(浪费大量内存),或者修改 Dani 的答案中的代码以使其表现得更像发电机(但没有好处!)。

真正的Python也有一个good article on generators if you want to learn more. And of course, check out the docs