【问题标题】:Use Python to extract Branch Lengths from Newick Format使用 Python 从 Newick 格式中提取分支长度
【发布时间】:2014-04-19 16:06:22
【问题描述】:

我在 python 中有一个列表,其中包含一个项目,它是以 Newick 格式编写的树,如下所示:

['(BMNH833953:0.16529463651919140688,(((BMNH833883:0.22945757727367316336,(BMNH724182a:0.18028180766761139897,(BMNH724182b:0.21469677818346077913,BMNH724082:0.54350916483644962085):0.00654573856803835914):0.04530853441176059537):0.02416511342888815264,(((BMNH794142:0.21236619242575086042,(BMNH743008:0.13421900772403019819,BMNH724591:0.14957653992840658219):0.02592135486124686958):0.02477670174791116522,BMNH703458a:0.22983459269245612444):0.00000328449424529074,BMNH703458b:0.29776257618061197086):0.09881729077887969892):0.02257522897558370684,BMNH833928:0.21599133163597591945):0.02365043128986757739,BMNH724053:0.16069861523756587274):0.0;']

在树格式中,如下所示:

我正在尝试编写一些代码来查看列表项并返回 ID (BMNHxxxxxx),这些 ID (BMNHxxxxxx) 由 0 的分支长度(例如

JustTree = []
with JustTree as f:
    for match in re.finditer(r"(?<=Item\sA)(?:(?!Item\sB).){50,}", subject, re.I):
        f.extend(match.group()+"\n") 

取自另一个 StackOverflow 答案,其中项目 A 将是 ':',因为分支长度总是出现在 a : 之后,而项目 B 可能是 ',' 或 ')' 或 ';'因为这三个字符将其定界,但我在正则表达式方面的经验不足以做到这一点。

在这种情况下,通过使用 0 的分支长度,我希望代码输出 ['BMNH703458a', 'BMNH703458b']。如果我可以将其更改为还包括由用户定义值的分支长度(例如 0.01)连接的 ID,这将非常有用。

如果有人有任何意见,或者可以指出一个有用的答案,我将不胜感激。

【问题讨论】:

  • 但对我来说,这两个 ID 不是由0 的分支长度连接,而是由0.00000328449424529074 的分支长度连接。是否有某种程度的精确度您认为微不足道?
  • @Jerry 道歉,我会编辑我的问题,是的,我假设 0.00000328449424529074 与 0 没有显着差异
  • 虽然,这在此特定示例中有效,但在所有示例中均无效。因此,为了解释 newick 格式,假设我们有一棵树,其中包含三个物种:A、B 和 C,其中 A 和 B 与 C 的相关性更高。在树中,我上传了查看红色突出显示的树枝正上方的三个物种,看看我是说。在 Newick 格式中,这将被写为 ((A,B),C)。要包括分支长度,请在“:”之后添加长度。因此,虽然您的示例在这种情况下有效,但您可以看到,通过增加变量 0\.000,它将开始将不密切相关的 ID 放在一起。
  • 我想解决这个问题的方法是将所有分支长度提取到一个列表(BranchLst1)中,将低于用户定义输入的那些添加到另一个列表(SmallBranchLst2)然后匹配这些分支回到原来的 Newick Tree 列表。我可以做第二点,但我不能制作一个从 Newick 树列表中提取所有分支长度并将它们放入另一个列表的正则表达式
  • 谢谢,感谢您的帮助!是的,相关的 ID 将是相同的,如果它更容易我们可以忽略 a 或 b,因为我添加了它以帮助自己识别应该一起使用的 ID。这意味着树中的所有 ID 都是相同的,它们以 BMNH 开头并以 6 个数字结尾

标签: python regex dna-sequence phylogeny


【解决方案1】:

好的,这是一个仅提取数字(可能带有小数)的正则表达式:

\b[0-9]+(?:\.[0-9]+)?\b

\bs 确保其旁边的数字周围没有其他数字、字母或下划线。这叫做词界。

[0-9]+ 匹配多个数字。

(?:\.[0-9]+)? 是一个可选组,这意味着它可能匹配也可能不匹配。如果在第一个 [0-9]+ 之后有一个点和数字,那么它将匹配那些。否则,它不会。该组本身匹配一个点,并且至少匹配一个数字。

您可以将它与re.findall 一起使用以将所有匹配项放在一个列表中:

import re
NewickTree = ['(BMNH833953:0.16529463651919140688,(((BMNH833883:0.22945757727367316336,(BMNH724182a:0.18028180766761139897,(BMNH724182b:0.21469677818346077913,BMNH724082:0.54350916483644962085):0.00654573856803835914):0.04530853441176059537):0.02416511342888815264,(((BMNH794142:0.21236619242575086042,(BMNH743008:0.13421900772403019819,BMNH724591:0.14957653992840658219):0.02592135486124686958):0.02477670174791116522,BMNH703458a:0.22983459269245612444):0.00000328449424529074,BMNH703458b:0.29776257618061197086):0.09881729077887969892):0.02257522897558370684,BMNH833928:0.21599133163597591945):0.02365043128986757739,BMNH724053:0.16069861523756587274):0.0;']

pattern = re.compile(r"\b[0-9]+(?:\.[0-9]+)?\b")

for tree in NewickTree:
    branch_lengths = pattern.findall(tree)
    # Do stuff to the list branch_lengths
    print(branch_lengths)

对于此列表,您可以打印以下内容:

['0.16529463651919140688', '0.22945757727367316336', '0.18028180766761139897',
 '0.21469677818346077913', '0.54350916483644962085', '0.00654573856803835914', 
 '0.04530853441176059537', '0.02416511342888815264', '0.21236619242575086042',
 '0.13421900772403019819', '0.14957653992840658219', '0.02592135486124686958', 
 '0.02477670174791116522', '0.22983459269245612444', '0.00000328449424529074',
 '0.29776257618061197086', '0.09881729077887969892', '0.02257522897558370684',
 '0.21599133163597591945', '0.02365043128986757739', '0.16069861523756587274',
 '0.0']

【讨论】:

  • 正则表达式可以简化为r"\b[\d.]+"。您可以将字符串转换为浮点数:branch_lengths = [float(x) for x in branch_lengths]
  • 简化并不总是意味着更好。该正则表达式还将匹配很多点,以及\d 可以匹配的除英文数字之外的任何其他字符。
  • 只是想提供帮助,杰瑞。 :)
  • 我只是说为什么这不一定会更好:)
  • 虽然转换为浮点数是个好主意,但我相信 OP 可以自己解决这个问题。 :) 看看你是否可以更好地实现下面的嵌套列表例程。我觉得它在 python 上不是最理想的。
【解决方案2】:

我知道您的问题已得到解答,但如果您希望将数据作为嵌套列表而不是扁平字符串:

import re
import pprint

a="(BMNH833953:0.16529463651919140688,(((BMNH833883:0.22945757727367316336,(BMNH724182a:0.18028180766761139897,(BMNH724182b:0.21469677818346077913,BMNH724082:0.54350916483644962085):0.00654573856803835914):0.04530853441176059537):0.02416511342888815264,(((BMNH794142:0.21236619242575086042,(BMNH743008:0.13421900772403019819,BMNH724591:0.14957653992840658219):0.02592135486124686958):0.02477670174791116522,BMNH703458a:0.22983459269245612444):0.00000328449424529074,BMNH703458b:0.29776257618061197086):0.09881729077887969892):0.02257522897558370684,BMNH833928:0.21599133163597591945):0.02365043128986757739,BMNH724053:0.16069861523756587274):0.0;"

def tokenize(str):
  for m in re.finditer(r"\(|\)|[\w.:]+", str):
    yield m.group()

def make_nested_list(tok, L=None):
  if L is None: L = []
  while True:
    try: t = tok.next()
    except StopIteration: break
    if   t == "(": L.append(make_nested_list(tok))
    elif t == ")": break
    else:
      i = t.find(":"); assert i != -1
      if i == 0: L.append(float(t[1:]))
      else:      L.append([t[:i], float(t[i+1:])])
  return L

L = make_nested_list(tokenize(a))
pprint.pprint(L)

【讨论】:

    【解决方案3】:

    有几个 Python 库支持 newick 格式。 ETE toolkit 允许读取 newick 字符串并将树作为 Python 对象进行操作:

    from ete2 import Tree
    tree = Tree(newickFile)
    print tree
    

    几个 newick 子格式可以是 choosen 并且分支距离被解析,即使它们以科学计数法表示。

    from ete2 import Tree
    tree = Tree("(A:3.4, (B:0.15E-10,C:0.0001):1.5E-234);")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      • 2012-01-25
      • 2012-03-18
      • 2019-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多