如何为给定外群的一组物种生成所有可能的Newick树排列?在
对于那些不知道Newick树格式是什么的人,可以在以下网站上找到一个很好的描述: https://en.wikipedia.org/wiki/Newick_format
我想为给定一个外群的一组物种创建所有可能的Newick树排列。我希望处理的叶节点数很可能是4、5或6个叶节点。在
“软”和“硬”多原子都是允许的。 https://en.wikipedia.org/wiki/Polytomy#Soft_polytomies_vs._hard_polytomieshttps://biology.stackexchange.com/questions/23667/evidence-discussions-of-hard-polytomy
下面显示的是理想的输出,将“E”设置为outgroup
理想输出:
((("A","B","C"),("D"),("E"));
((("A","B","D"),("C"),("E"));
((("A","C","D"),("B"),("E"));
((("B","C","D"),("A"),("E"));
((("A","B")("C","D"),("E"));
((("A","C")("B","D"),("E"));
((("B","C")("A","D"),("E"));
(("A","B","C","D"),("E"));
(((("A","B"),"C"),"D"),("E"));
但是,我使用itertools提供的任何可能的解决方案,特别是itertools.排列,遇到了等效输出的问题。我想到的最后一个想法涉及到如下所示的等效输出。在
等效输出:
^{pr2}$这是我的解决方案的开始。不过,除了itertools之外,我现在还不知道该怎么解决这个问题。在
import itertools
def Newick_Permutation_Generator(list_of_species, name_of_outgroup)
permutations_list =(list(itertools.permutations(["A","B","C","D","E"])))
for given_permutation in permutations_list:
process(given_permutation)
Newick_Permutation_Generator(["A","B","C","D","E"], "E")
作为叶子集合的递归集合的树
让我们暂时把newick表示放在一边,考虑一下这个问题的一个可能的python表示。在
根树可以看作是(set of(sets of(sets of…))叶的递归层次结构。集合是无序的,这非常适合于描述树中的类:}相同。在
{{{"A", "B"}, {"C", "D"}}, "E"}
应该与{如果我们考虑叶的初始集}构建的树集。我们可以尝试编写一个递归的
{"A", "B", "C", "D", "E"}
,那么以“E”为外群的树是形式为{tree, "E"}
的集合,其中tree
来自可以从叶子集{trees
函数来生成这组树,我们的全部树集将表示如下:(这里,我使用set comprehension表示法。)
实际上,python不允许集合集合,因为集合的元素必须是“散列的”(也就是说,python必须能够计算对象的一些“散列”值,以便能够检查它们是否属于集合)。python集合没有这个属性。幸运的是,我们可以使用一个类似的名为^{} 的数据结构,它的行为非常类似于一个集合,但是不能被修改并且是“散列”的。因此,我们的一组树将是:
^{pr2}$实现
trees
函数现在让我们关注
trees
函数。在对于叶集的每个可能的分区(分解为一组不相交的子集,包括所有元素),我们需要为分区的每个部分找到所有可能的树(通过递归调用)。对于一个给定的分区,我们将为每个可能的子树组合生成一个树。在
例如,如果一个分区是
{"A", {"B", "C", "D"}}
,我们将考虑所有可以由部分"A"
生成的树(实际上,只是叶"A"
本身),以及可以由部分{"B", "C", "D"}
(即trees({"B", "C", "D"})
)生成的所有可能的树。然后,通过获取所有可能的对,其中一个元素来自"A"
,另一个元素来自trees({"B", "C", "D"})
,就可以得到这个分区的可能树。在这可以推广到包含两个以上部分的分区,并且
itertools
中的product
函数在这里似乎很有用。在因此,我们需要一种方法来生成一组叶子的可能分区。在
生成集合的划分
在这里,我根据this solution创建了一个
partitions_of_set
函数:为了检查获得的分区,我们创建了一个函数,使它们更易于显示(这对于以后生成树的newick表示也很有用):
我们测试分区是否有效:
输出:
的实际代码trees
函数现在我们可以编写
tree
函数:测试:
输出:
我希望结果是正确的。在
这种方法有点棘手。我花了一些时间来找出如何避免无限递归(当分区是
{{"A", "B", "C", "D"}}
时就会发生这种情况)。在这是个很难回答的问题!这是我的旅程。在
第一个观察是outgroup始终是一个连接到newick字符串末尾的节点。让我们把其余的物种称为内群,并尝试生成这些物种的所有排列。然后简单地添加outgroup。在
这将返回40个newick字符串:
^{pr2}$其中有些是重复的,但我们稍后将删除这些重复项。在
作为bli noted in the comments,
(((("A","B"),"C"),"D"),("E"));
及其变体也应被视为有效解。 comments on BioStar向我指出了正确的方向,这与生成二叉树的所有可能的分组是一样的。我找到了一个漂亮的Python implementation in this StackOverflow answer by rici:然后
生成以下15个新图标:
所以现在我们已经有了40+15=55个可能的newick字符串,我们必须删除重复项。在
我尝试的第一个死胡同是为每个newick字符串创建一个规范化的表示,这样我就可以将它们用作字典中的键。其想法是递归地对所有节点中的字符串进行排序。但首先我必须捕获所有(嵌套)节点。我不能使用正则表达式,因为nested structures are by definition not regular。在
因此,我使用了
pyparsing
包,并提出了这个:这让我屈服了
有22个键的字典:
但仔细检查发现了一些问题。让我们看看newick}。但事实上,这些是重复的树。我们可以通过观察两棵树之间的Robinson-Foulds distance来证实这一点。如果它是零,树是相同的。在
'(((A, B), (C, D)),(E));
和((D, C), (A, B),(E));
的例子。在我们的字典d
中,它们具有不同的规范密钥,分别是[[[['A', 'B'], ['C', 'D']], ['E']]]
和{我们使用ete3 toolkit package中的
robinson_foulds
函数好的,那么Robinson Foulds是一个更好的方法来检查newick树的等式,而不是我的标准树方法。让我们将所有newick字符串包装在一个自定义的
MyTree
对象中,其中相等被定义为Robinson-Foulds距离为零:如果我们还可以定义一个
__hash__()
函数,为重复树返回相同的值,那么set(trees)
将自动删除所有重复项。在不幸的是,I haven't been able to find a good way to define ^{} ,但是有了} :
__eq__
,我可以make use of ^{所以,我们的旅程到此结束了。我不能完全证明这是正确的解决方案,但我很有信心,以下19个newick都是可能的不同排列:
如果我们将每个newick与所有其他newick成对比较,就可以确认这个列表中不再有重复项了
相关问题 更多 >
编程相关推荐