我想输入一个DNA序列,并制作某种生成器,产生具有特定突变频率的序列。例如,假设我有DNA链"ATGTCGTCACACACCGCAGATCCGTGTTTGAC",我想要制造T->A频率为5%的突变。我该如何创造这个呢?我知道创建随机突变可以用这样的代码来完成:
import random
def mutate(string, mutation, threshold):
dna = list(string)
for index, char in enumerate(dna):
if char in mutation:
if random.random() < threshold:
dna[index] = mutation[char]
return ''.join(dna)
但我真的不知道该怎么做,就是做一个固定的突变频率。有人知道怎么做吗?谢谢。
编辑:
所以,如果我使用字节数组,那么格式应该是这样的,因为我得到了一个错误:
import random
dna = "ATGTCGTACGTTTGACGTAGAG"
def mutate(dna, mutation, threshold):
dna = bytearray(dna) #if you don't want to modify the original
for index in range(len(dna)):
if dna[index] in mutation and random.random() < threshold:
dna[index] = mutation[char]
return dna
变异( dna,{"A":"T"},0.05)打印(“我的dna现在:”,dna)
错误:"TypeError:没有编码的字符串参数“
编辑2:
import random
myDNA = bytearray("ATGTCGTCACACACCGCAGATCCGTGTTTGAC")
def mutate(dna, mutation, threshold):
dna = myDNA # if you don't want to modify the original
for index in range(len(dna)):
if dna[index] in mutation and random.random() < threshold:
dna[index] = mutation[char]
return dna
mutate(dna, {"A": "T"}, 0.05)
print("my dna now:", dna)
产生错误
发布于 2014-05-31 22:53:51
你问我关于打印所有可能的突变的函数,这就是。输出的数量随着输入数据的长度呈指数增长,因此函数只打印可能性,而不以某种方式存储它们(这会消耗大量内存)。我创建了一个递归函数,这个函数不应该用很大的输入,我还会添加一个非递归函数,它的工作没有问题或限制。
def print_all_possibilities(dna, mutations, index = 0, print = print):
if index < 0: return #invalid value for index
while index < len(dna):
if chr(dna[index]) in mutations:
print_all_possibilities(dna, mutations, index + 1)
dnaCopy = bytearray(dna)
dnaCopy[index] = ord(mutations[chr(dna[index])])
print_all_possibilities(dnaCopy, mutations, index + 1)
return
index += 1
print(dna.decode("ascii"))
# for testing
print_all_possibilities(bytearray(b"AAAATTTT"), {"A": "T"})
这对于我在python 3上是有用的,如果您愿意的话,我也可以解释代码。
注意:这个函数需要一个字节数组,就像函数测试中给出的那样。
解释:
这个函数在dna中搜索一个可能发生突变的位置,从索引开始,所以它通常从0开始,一直到最后。这就是为什么每次执行循环时都增加索引的while-循环是for (它基本上是一个正常的迭代,就像for循环一样)。如果函数找到可以发生突变的位置(if chr(dna[index]) in mutations:
),那么它会复制dna并允许第二个变异(dnaCopy[index] = ord(mutations[chr(dna[index])])
,注意字节数组是一个数值数组,所以我一直使用chr和ord在字符串和int之间进行更改)。在那之后,这个函数再次被调用来寻找更多的可能的突变,所以这些函数再次寻找两个可能的dna中可能的突变,但是它们跳过了他们已经扫描过的点,所以它们开始于index + 1
。在此之后,打印的顺序将传递给被调用的函数print_all_possibilities,因此我们不必再做任何事情,并且退出使用return
的执行。如果我们没有发现任何突变,我们打印我们可能的dna,因为我们不再调用该功能,所以没有其他人会这样做。
这听起来可能很复杂,但它或多或少是一个优雅的解决方案。另外,要理解递归,你必须理解递归,所以如果你现在还不理解递归,就不要费心了。如果你在一张纸上试用这个方法会有帮助:把一个简单的dna字符串"TTATTATTA“与可能的突变"A”-> "T“(所以我们有8种可能的突变)一起做,然后这样做:从左到右遍历字符串,如果你找到一个位置,序列可以变异(这里只是”A“),再次写下这条字符串,这一次让字符串在给定的位置发生变异,这样你的第二个字符串就和原来的稍有不同了。在原件和副本中,标记你走了多远(可能在你允许变异的字母后面加上一个“x”),并将这个过程与副本作为新的原件重复。如果您没有发现任何可能的变异,那么在字符串下划线(这相当于打印它)。最后,您应该有8个不同的字符串,所有下划线。我希望这能有助于理解它。
编辑:这里的是非递归函数:
def print_all_possibilities(dna, mutations, printings = -1, print = print):
mut_possible = []
for index in range(len(dna)):
if chr(dna[index]) in mutations: mut_possible.append(index)
if printings < 0: printings = 1 << len(mut_possible)
for number in range(min(printings, 1 << len(mut_possible)):
dnaCopy = bytearray(dna) # don't change the original
counter = 0
while number:
if number & (1 << counter):
index = mut_possible[counter]
dnaCopy[index] = ord(mutations[chr(dna[index])])
number &= ~(1 << counter)
counter += 1
print(dnaCopy.decode("ascii"))
# for testing
print_all_possibilities(bytearray(b"AAAATTTT"), {"A": "T"})
该函数附带一个附加参数,可以控制最大输出的数量。
print_all_possibilities(bytearray(b"AAAATTTT"), {"A": "T"}, 5)
将只打印5个结果。
Explanation:
如果你的dna有x个可能发生变异的位置,那么你就有2^x可能的突变,因为dna在每一个地方都可以变异。这个函数找到你的dna可以变异的所有位置,并将它们存储在mut_possible
中(这是for循环的代码)。现在,mut_possible
包含了dna可以变异的所有位置,因此我们有2^ len(mut_possible)
(len(mut_possible)
是mut_possible中元素的数量)可能的突变。我写了1 << len(mut_possible)
,它是一样的,但更快。如果printings
是负数,则函数将决定打印所有可能性,并将打印设置为可能性数。如果打印为正数,但低于可能性数,则函数将只打印printings
突变,因为min(printings, 1 << len(mut_possible))
将返回较小的数字,即printings
。否则,函数将打印出所有的可能性。现在我们有了number
通过range(...)
,所以这个循环,每次打印一个突变,将执行所需的次数。而且,每次都会增加一个。(例如,范围(4)是相似的!到0,1,2,3)。接下来,我们使用数字来创建一个突变。要理解这一步,您必须了解二进制数。如果我们的数字是10,它是二进制1010。这些数字告诉我们我们必须在哪里修改dna代码(dnaCopy
)。第一个位是0,所以我们不修改可能发生突变的第一个位置,下一个位是1,所以我们修改这个位置,然后是0等等……若要“读取”使用变量counter
的位,请执行以下操作。number & (1 << counter)
将返回一个非零值,如果设置了counter
第四位,那么如果设置了这个位,我们就会在可能发生突变的counter
第四位置修改我们的dna。这是用mut_possible编写的,所以我们想要的位置是mut_possible[counter]
。当我们在那个位置变异我们的dna后,我们把这个位设置为0,以表明我们已经修改了这个位置。这是用number &= ~(1 << counter)
完成的。在此之后,我们增加计数器来查看其他位元。如果number不是0,则while循环将继续执行,因此,如果number至少设置了一位(如果我们必须修改至少一个dna位置)。在我们修改了dnaCopy之后,we循环就完成了,我们打印结果。
我希望这些解释能有所帮助。我发现你对python是新手,所以如果您有任何进一步的问题,请花时间让它沉入其中,并与我联系。
发布于 2014-05-31 20:29:24
看完我的文章后,这个问题似乎很容易回答。很有可能我误解了什么,所以如果我错了,请纠正我。
如果你想要5%的机会用A改变T,那么你应该写
mutate(yourString, {"A": "T"}, 0.05)
我还建议您使用字节数组而不是字符串。字节数组类似于字符串,它只能包含字节(值从0到255),而字符串可以包含更多的字符,但是字节数组是可变的。通过使用字节数组,您不需要创建临时列表或最终加入它。如果这样做,您的代码如下所示:
import random
def mutate(dna, mutation, threshold):
if isinstance(dna, str):
dna = bytearray(dna, "utf-8")
else:
dna = bytearray(dna)
for index in range(len(dna)):
if chr(dna[index]) in mutation and random.random() < threshold:
dna[index] = ord(mutation[chr(dna[index])])
return dna
dna = "ATGTCGTACGTTTGACGTAGAG"
print("DNA first:", dna)
newDNA = mutate(dna, {"A": "T"}, 0.05)
print("DNA now:", newDNA.decode("ascii")) #use decode to make newDNA a string
在我遇到了字节数组版本的所有愚蠢问题之后,下面是对字符串进行操作的版本:
import random
def mutate(string, mutation, threshold):
dna = list(string)
for index, char in enumerate(dna):
if char in mutation:
if random.random() < threshold:
dna[index] = mutation[char]
return ''.join(dna)
dna = "ATGTCGTACGTTTGACGTAGAG"
print("DNA first:", dna)
newDNA = mutate(dna, {"A": "T"}, 0.05)
print("DNA now:", newDNA)
如果使用具有较大输入的字符串版本,则计算时间和所使用的内存都会更大。当你想用更大的输入来完成这个任务时,字节数组版本将是最好的。
https://stackoverflow.com/questions/23974199
复制相似问题