data.frame 到 Newick
我在计算系统发育学方面获得了博士学位,并且在我制作这段代码的过程中,当我获得一些非标准格式(在系统发育意义上)的数据时,我使用了一次或两次。该脚本遍历数据帧,就好像它是一棵树......并一路将内容粘贴到 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=""))
}
主函数 df2newick() 有两个参数:
-
df 是要转换的数据框(data.frame 类的对象)
-
innerlabel 告诉函数为内部节点编写标签(布尔型)
在您的示例中进行演示:
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));"
现在你可以用来自猿的read.tree() 将它读入phylo 类的对象
library(ape)
mytree <- read.tree(text=myNewick)
plot(mytree)
如果你想给 Newick 字符串添加内部节点标签,你可以使用这个:
myNewick <- df2newick(df, TRUE)
#[1] "((Abb,Acc)A,((Bad,Bae)Ba,Bdd)B);"
希望这是有用的(也许我的博士学位不是一个完整的时间;-)
数据框格式的附加说明:
正如您所观察到的,df2newick 函数忽略了一个孩子的内部模式(无论如何最好与大多数系统发育方法一起使用......仅与我相关)。我最初获得并与此脚本一起使用的 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);"
这对我来说真的很奇怪,但我添加它以防万一,因为它现在确实包含了原始数据帧中的所有信息。