我有一个data.frame对象。举个简单的例子:
> data.frame(x=c('A','A','B','B','B'), y=c('Ab','Ac','Ba', 'Ba','Bd'), z=c('Abb','Acc','Bad', 'Bae','Bdd'))
x y z
1 A Ab Abb
2 A Ac Acc
3 B Ba Bad
4 B Ba Bae
5 B Bd Bdd
实际数据中有更多的行和列。我怎么能像这样创建树状图的嵌套树结构对象:
|---Ab---Abb
A---|
| |---Ac---Acc
--| /--Bad
| |---Ba-------|
B---| \--Bae
|---Bb---Bdd
答案 0 :(得分:16)
我在计算系统发育学方面取得了博士学位,并且在我制作这段代码的过程中,我使用了这种非标准格式(在系统发育意义上)获得了一些数据时使用过一次或两次。该脚本遍历数据帧,就好像它是一个树...并沿途粘贴到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
告诉函数为内部节点写入标签(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()
来自ape
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);"
这对我来说真的很奇怪,但我添加它以防万一,因为它现在真的包含了原始数据帧中的所有信息。
答案 1 :(得分:1)
我对R中的树形图的内部结构了解不多,但下面的代码将创建一个嵌套的列表结构,其中包含我认为您寻找的层次结构:
stree = function(x,level=0) {
#x is a string vector
#resultis a hierarchical structure of lists (that contains lists, etc.)
#the names of the lists are the node values.
level = level+1
if (length(x)==1) {
result = list()
result[[substring(x[1],level)]]=list()
return(result)
}
result=list()
this.level = substring(x,level,level)
next.levels = unique(this.level)
for (p in next.levels) {
if (p=="") {
result$p = list()
} else {
ids = which(this.level==p)
result[[p]] = stree(x[ids],level)
}
}
result
}
它在字符串向量上运行。所以如果你的数据帧你需要打电话 应力状态(as.character(DF [1,3]))
希望这有帮助。