如何将数据帧转换为树形结构对象,如树形图



我有一个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

data.frame to 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()从ape读取它到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);"

这对我来说很奇怪,但我还是添加了它,因为它现在包含了原始数据框中的所有信息

我不太了解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
}

操作的对象是string类型的vector对象。所以在数据框架的情况下,需要调用stree (as.character (df [3]))

相关内容

  • 没有找到相关文章

最新更新