data.frameからNewickへ
私は計算系統学の博士号を取得し、このコードを作成する途中のどこかで、この非標準形式(系統発生の意味で)のデータを取得するときに1〜2回使用しました。スクリプトは、まるでツリーであるかのようにデータフレームをトラバースし、途中でNewick文字列に貼り付けます。これは標準形式であり、任意の種類のツリーオブジェクトに変換できます。
スクリプトは最適化できると思いますが(あまり使用しないので、全体的な効率が低下します)、少なくとも、ハードドライブに散らばっているほこりを集めるよりも共有する方がよいでしょう。
## recursion function
traverse <- function(a,i,innerl){
if(i < (ncol(df))){
alevelinner <- as.character(unique(df[which(as.character(df[,i])==a),i+1]))
desc <- NULL
if(length(alevelinner) == 1) (newickout <- traverse(alevelinner,i+1,innerl))
else {
for(b in alevelinner) desc <- c(desc,traverse(b,i+1,innerl))
il <- NULL; if(innerl==TRUE) il <- a
(newickout <- paste("(",paste(desc,collapse=","),")",il,sep=""))
}
}
else { (newickout <- a) }
}
## data.frame to newick function
df2newick <- function(df, innerlabel=FALSE){
alevel <- as.character(unique(df[,1]))
newick <- NULL
for(x in alevel) newick <- c(newick,traverse(x,1,innerlabel))
(newick <- paste("(",paste(newick,collapse=","),");",sep=""))
}
main関数df2newick()
は2つの引数を取ります。
df
これは変換されるデータフレームです(クラスdata.frameのオブジェクト)
innerlabel
これは、関数に内部ノードのラベルを書き込むように指示します(bulean)
あなたの例でそれを示すために:
df <- data.frame(x=c('A','A','B','B','B'), y=c('Ab','Ac','Ba', 'Ba','Bd'), z=c('Abb','Acc','Bad', 'Bae','Bdd'))
myNewick <- df2newick(df)
#[1] "((Abb,Acc),((Bad,Bae),Bdd));"
phylo
これでread.tree()
、fromapeを使用してクラスのオブジェクトに読み込むことができます。
library(ape)
mytree <- read.tree(text=myNewick)
plot(mytree)
Newick文字列に内部ノードラベルを追加する場合は、次を使用できます。
myNewick <- df2newick(df, TRUE)
#[1] "((Abb,Acc)A,((Bad,Bae)Ba,Bdd)B);"
これがお役に立てば幸いです(そしておそらく私の博士号は完全な時間の腰ではありませんでした;-)
データフレーム形式に関する追加の注意事項:
ご覧のとおり、df2newick関数は、1つの子を持つ内部モードを無視します(とにかく、ほとんどの系統発生方法で使用するのが最適です...私にのみ関連していました)。このdf
スクリプトで最初に取得して使用したオブジェクトは、次の形式でした。
df <- data.frame(x=c('A','A','B','B','B'), y=c('Abb','Acc','Ba', 'Ba','Bdd'), z=c('Abb','Acc','Bad', 'Bae','Bdd'))
あなたのものと非常に似ています...しかし、「内部単一の子ノード」はそれらの子と同じ名前を持っていましたが、このノードにも異なる内部名があり、名前は無視されます...関連性がないかもしれませんが、あなたはできます次のように、再帰関数の一部を無視してください。
traverse <- function(a,i,innerl){
if(i < (ncol(df))){
alevelinner <- as.character(unique(df[which(as.character(df[,i])==a),i+1]))
desc <- NULL
##if(length(alevelinner) == 1) (newickout <- traverse(alevelinner,i+1,innerl))
##else {
for(b in alevelinner) desc <- c(desc,traverse(b,i+1,innerl))
il <- NULL; if(innerl==TRUE) il <- a
(newickout <- paste("(",paste(desc,collapse=","),")",il,sep=""))
##}
}
else { (newickout <- a) }
}
そして、あなたはこのようなものを得るでしょう:
[1] "(((Abb)Ab,(Acc)Ac)A,((Bad,Bae)Ba,(Bdd)Bd)B);"
これは私には本当に奇妙に見えますが、念のために追加します。これは、元のデータフレームからのすべての情報が実際に含まれているためです。