8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Biopython】Bio.Phyloを利用した系統樹操作まとめ

Last updated at Posted at 2021-06-29

BiopythonのBio.Phyloを利用した系統樹操作まとめ

系統樹操作まとめ内容

系統樹データ読み込み

Bio.Phylo.read()メソッドで系統樹データ読み込み

実行ソース
from io import StringIO

from Bio import Phylo
from Bio.Phylo.BaseTree import Tree

treedata = "((((A:1,B:1)100:1,(C:1,D:1)100:1)100:1,(E:2,F:2)90:1):1,G:4)100;"
tree: Tree = Phylo.read(file=StringIO(treedata), format="newick")
print(tree)
出力結果
Tree(rooted=False, weight=1.0)
    Clade(confidence=100)
        Clade(branch_length=1.0)
            Clade(branch_length=1.0, confidence=100)
                Clade(branch_length=1.0, confidence=100)
                    Clade(branch_length=1.0, name='A')
                    Clade(branch_length=1.0, name='B')
                Clade(branch_length=1.0, confidence=100)
                    Clade(branch_length=1.0, name='C')
                    Clade(branch_length=1.0, name='D')
            Clade(branch_length=1.0, confidence=90)
                Clade(branch_length=2.0, name='E')
                Clade(branch_length=2.0, name='F')
        Clade(branch_length=4.0, name='G')

系統樹の可視化

Bio.Phylo.draw()メソッドでTreeオブジェクトの系統樹情報を可視化

実行ソース
Phylo.draw(tree)

出力結果
phylogenetic_tree.png

全ノード取得

Treeオブジェクトのfind_clades()メソッドで取得
各ノードはそれぞれ 1.name, 2.branch_length(枝長), 3.confidence(ブートストラップ値), 4.clades(子孫ノードリスト)プロパティを格納

実行ソース
for node in tree.find_clades():
    print(f"Node name = {node.name}, ", end="")
    print(f"Branch length = {node.branch_length}, ", end="")
    print(f"Confidence = {node.confidence}, ", end="")
    print(f"Descendants = {node.clades}")
出力結果
Node name = None, Branch length = None, Confidence = 100, Descendants = [Clade(branch_length=1.0), Clade(branch_length=4.0, name='G')]
Node name = None, Branch length = 1.0, Confidence = None, Descendants = [Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=90)]
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100)]
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, name='A'), Clade(branch_length=1.0, name='B')]
Node name = A, Branch length = 1.0, Confidence = None, Descendants = []
Node name = B, Branch length = 1.0, Confidence = None, Descendants = []
Node name = None, Branch length = 1.0, Confidence = 100, Descendants = [Clade(branch_length=1.0, name='C'), Clade(branch_length=1.0, name='D')]
Node name = C, Branch length = 1.0, Confidence = None, Descendants = []
Node name = D, Branch length = 1.0, Confidence = None, Descendants = []
Node name = None, Branch length = 1.0, Confidence = 90, Descendants = [Clade(branch_length=2.0, name='E'), Clade(branch_length=2.0, name='F')]
Node name = E, Branch length = 2.0, Confidence = None, Descendants = []
Node name = F, Branch length = 2.0, Confidence = None, Descendants = []
Node name = G, Branch length = 4.0, Confidence = None, Descendants = []

終端ノードのみ取得

Treeオブジェクトのget_terminals()メソッドにより取得
count_terminals()メソッドにより終端ノード数の取得も可能

実行ソース
print(tree.get_terminals())
print("終端ノード数 =", tree.count_terminals()
出力結果
[Clade(branch_length=1.0, name='A'), Clade(branch_length=1.0, name='B'), Clade(branch_length=1.0, name='C'), Clade(branch_length=1.0, name='D'), Clade(branch_length=2.0, name='E'), Clade(branch_length=2.0, name='F'), Clade(branch_length=4.0, name='G')]
終端ノード数 = 7

内部ノードのみ取得

Treeオブジェクトのget_nonterminals()メソッドにより取得

実行ソース
print(tree.get_nonterminals())
print("内部ノード数 =", len(list(tree.get_nonterminals())))
出力結果
[Clade(confidence=100), Clade(branch_length=1.0), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=100), Clade(branch_length=1.0, confidence=90)]
内部ノード数 = 6

ノードプロパティ変更

各ノード(Cladeオブジェクト)プロパティは下記のように変更可能
個人的には内部ノードに一意的な識別子を与える目的で利用することが多い。

実行ソース
for cnt, node in enumerate(tree.get_nonterminals()):
    if node.name is None:
        node.name = f"N{cnt}"
Phylo.draw(tree)

出力結果
add_nodes_property.png

ノード検索

Treeオブジェクトのfind_clades()メソッドでノード検索・取得
メソッド引数により検索対象・方法を設定可能

実行ソース
# 単純検索
print(list(tree.find_clades("A")))
print(list(tree.find_clades("N1")))
# 終端ノードのみを対象として検索
print(list(tree.find_clades("N1", terminal=True)))
# nameプロパティを対象として、正規表現検索
print(list(tree.find_clades({"name": "N.*"})))
# confidenceプロパティを対象として検索
print(list(tree.find_clades({"confidence": 90})))
出力結果
[Clade(branch_length=1.0, name='A')]
[Clade(branch_length=1.0, name='N1')]
[]
[Clade(confidence=100, name='N0'), Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N3'), Clade(branch_length=1.0, confidence=100, name='N4'), Clade(branch_length=1.0, confidence=90, name='N5')]
[Clade(branch_length=1.0, confidence=90, name='N5')]

終端ノード群の単系統判定

Treeオブジェクトのis_monophyletic()メソッドにより対象とする終端ノード群が単系統か判定

  • 対象が単系統である場合、単系統のノード名を返す
  • 対象が単系統でない場合、Falseを返す
実行ソース
leaf_node_A = next(tree.find_clades("A"))
leaf_node_B = next(tree.find_clades("B"))
leaf_node_C = next(tree.find_clades("C"))
leaf_node_D = next(tree.find_clades("D"))

print("A-B単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B))
print("A-C単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_C))
print("A-B-C-D単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B, leaf_node_C, leaf_node_D))
出力結果
A-B単系統ノード = N3
A-C単系統ノード = False
A-B-C-D単系統ノード = N2

ルートから対象ノードまでの全ノード経路リスト取得

Treeオブジェクトのget_path()メソッドで取得
(全ノード経路リストにはルートの情報は含まない)

実行ソース
print("N3ノードまでの経路\n", tree.get_path(target="N3"))
print("Cノードまでの経路\n", tree.get_path(target="C"))
出力結果
N3ノードまでの経路
 [Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N3')]
Cノードまでの経路
 [Clade(branch_length=1.0, name='N1'), Clade(branch_length=1.0, confidence=100, name='N2'), Clade(branch_length=1.0, confidence=100, name='N4'), Clade(branch_length=1.0, name='C')]

最近共通祖先ノード取得

Treeオブジェクトのcommon_ancestor()メソッドにより、引数指定の対象ノード群における最近共通祖先ノード取得

実行ソース
mrca_node1 = tree.common_ancestor("E", "F")
print("E-F 最近共通祖先 =", mrca_node1.name)
mrca_node2 = tree.common_ancestor("N3", "N4")
print("N3-N4 最近共通祖先 =", mrca_node2.name)

mrca_node1.color = "red"
mrca_node1.width = 2
mrca_node2.color = "blue"
mrca_node2.width = 2
Phylo.draw(tree)
出力結果
E-F 最近共通祖先 = N5
N3-N4 最近共通祖先 = N2

mrca_tree.png

各ノード深さ取得

Treeオブジェクトのdepth()メソッドでノード深さ取得
(Key=各ノード,Value=対象ノードの深さ、としたディクショナリ形式)

実行ソース
print("枝の''で深さ算出\n", tree.depths(unit_branch_lengths=True))
print("枝の'長さ'で深さ算出\n", tree.depths(unit_branch_lengths=False)
出力結果
枝の'数'で深さ算出
{Clade(confidence=100, name='N0'): 0, Clade(branch_length=1.0, name='N1'): 1, Clade(branch_length=1.0, confidence=100, name='N2'): 2, Clade(branch_length=1.0, confidence=100, name='N3'): 3, Clade(branch_length=1.0, name='A'): 4, Clade(branch_length=1.0, name='B'): 4, Clade(branch_length=1.0, confidence=100, name='N4'): 3, Clade(branch_length=1.0, name='C'): 4, Clade(branch_length=1.0, name='D'): 4, Clade(branch_length=1.0, confidence=90, name='N5'): 2, Clade(branch_length=2.0, name='E'): 3, Clade(branch_length=2.0, name='F'): 3, Clade(branch_length=4.0, name='G'): 1}
枝の'長さ'で深さ算出
{Clade(confidence=100, name='N0'): 0, Clade(branch_length=1.0, name='N1'): 1.0, Clade(branch_length=1.0, confidence=100, name='N2'): 2.0, Clade(branch_length=1.0, confidence=100, name='N3'): 3.0, Clade(branch_length=1.0, name='A'): 4.0, Clade(branch_length=1.0, name='B'): 4.0, Clade(branch_length=1.0, confidence=100, name='N4'): 3.0, Clade(branch_length=1.0, name='C'): 4.0, Clade(branch_length=1.0, name='D'): 4.0, Clade(branch_length=1.0, confidence=90, name='N5'): 2.0, Clade(branch_length=2.0, name='E'): 4.0, Clade(branch_length=2.0, name='F'): 4.0, Clade(branch_length=4.0, name='G'): 4.0}

対象ノード間の枝長取得

Treeオブジェクトのdistance()メソッドにより引数指定の対象ノード間の枝長取得

実行ソース
print("A-B distance =", tree.distance(target1="A", target2="B"))
print("C-G distance =", tree.distance(target1="C", target2="G"))
print("N3-N5 distance =", tree.distance(target1="N3", target2="N5")
出力結果
A-B distance = 2.0
C-G distance = 8.0
N3-N5 distance = 3.0

系統樹全体の枝長総和取得

Treeオブジェクトのtotal_branch_length()メソッドで取得

実行ソース
print("枝長総和 =", tree.total_branch_length())
出力結果
枝長総和 = 17.0

全実行ソースまとめ

全実行ソース
from io import StringIO

from Bio import Phylo
from Bio.Phylo.BaseTree import Tree

print("### 系統樹データ読み込み ###")
treedata = "((((A:1,B:1)100:1,(C:1,D:1)100:1)100:1,(E:2,F:2)90:1):1,G:4)100;"
tree: Tree = Phylo.read(file=StringIO(treedata), format="newick")
print(tree)

print("### 系統樹の可視化 ###")
Phylo.draw(tree)

print("### 全ノード取得 ###")
for node in tree.find_clades():
    print(f"Node name = {node.name}, ", end="")
    print(f"Branch length = {node.branch_length}, ", end="")
    print(f"Confidence = {node.confidence}, ", end="")
    print(f"Descendants = {node.clades}")

print("### 終端ノードのみ取得 ###")
print(tree.get_terminals())
print("終端ノード数 =", tree.count_terminals())

print("### 内部ノードのみ取得 ###")
print(tree.get_nonterminals())
print("内部ノード数 =", len(list(tree.get_nonterminals())))

print("### ノードプロパティ変更 ###")
for cnt, node in enumerate(tree.get_nonterminals()):
    if node.name is None:
        node.name = f"N{cnt}"
Phylo.draw(tree)

print("### ノード検索 ###")
# 単純検索
print(list(tree.find_clades("A")))
print(list(tree.find_clades("N1")))
# 終端ノードのみを対象として検索
print(list(tree.find_clades("N1", terminal=True)))
# nameプロパティを対象として、正規表現検索
print(list(tree.find_clades({"name": "N.*"})))
# confidenceプロパティを対象として検索
print(list(tree.find_clades({"confidence": 90})))

print("### 終端ノード群の単系統判定 ###")
leaf_node_A = next(tree.find_clades("A"))
leaf_node_B = next(tree.find_clades("B"))
leaf_node_C = next(tree.find_clades("C"))
leaf_node_D = next(tree.find_clades("D"))

print("A-B単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B))
print("A-C単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_C))
print("A-B-C-D単系統ノード =", tree.is_monophyletic(leaf_node_A, leaf_node_B, leaf_node_C, leaf_node_D))

print("### ルートから対象ノードまでの全ノード経路リスト取得 ###")
print("N3ノードまでの経路\n", tree.get_path(target="N3"))
print("Cノードまでの経路\n", tree.get_path(target="C"))

print("### 最近共通祖先ノード取得 ###")
mrca_node1 = tree.common_ancestor("E", "F")
print("E-F 最近共通祖先 =", mrca_node1.name)
mrca_node2 = tree.common_ancestor("N3", "N4")
print("N3-N4 最近共通祖先 =", mrca_node2.name)

mrca_node1.color = "red"
mrca_node1.width = 2
mrca_node2.color = "blue"
mrca_node2.width = 2
Phylo.draw(tree)

print("### 各ノード深さ算出 ###")
print("枝の''で深さ算出\n", tree.depths(unit_branch_lengths=True))
print("枝の'長さ'で深さ算出\n", tree.depths(unit_branch_lengths=False))

print("### 対象ノード間の枝長取得 ###")
print("A-B distance =", tree.distance(target1="A", target2="B"))
print("C-G distance =", tree.distance(target1="C", target2="G"))
print("N3-N5 distance =", tree.distance(target1="N3", target2="N5"))

print("### 系統樹全体の枝長総和算出 ###")
print("枝長総和 =", tree.total_branch_length())

参考

Bio.Phylo.BaseTree module
Phylogenetics with Bio.Phylo

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?