【问题标题】:how to convert a data.frame to tree structure object such as dendrogram如何将 data.frame 转换为树状结构对象,例如树状图
【发布时间】:2013-02-26 21:50:32
【问题描述】:

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

【问题讨论】:

  • 你想绘制它还是有一个对象?如果是后者,那为什么不只是一个列表split(df$y, df$x)?或者您需要其中一个图形/树包..?
  • 我实际上两者都想要,所以 split(df$y, df$x) 不能很好地工作。 dendrogram 对象似乎是一个不错的对象。对不起,我没有说得更清楚。
  • 你检查过来自@Andrie 的ggdendro 包吗?
  • 是的,简单地说。据我了解,它主要是一个树状图绘图库。
  • @RNAer 你能举出第三级的例子吗?

标签: r dataframe dendrogram


【解决方案1】:

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);"

这对我来说真的很奇怪,但我添加它以防万一,因为它现在确实包含了原始数据帧中的所有信息。

【讨论】:

  • 我接受您的解决方案。结果我也写了一个脚本来把它转换成newick格式。
  • @RNA 请考虑在此处发布您的解决方案作为答案。
  • @Martin Turjak 如果硬盘中有灰尘,那就不好了。 ;] 感谢您的功能
【解决方案2】:

我对 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
}

它对字符串向量进行操作。因此,对于您的数据框,您需要调用 stree(as.character(df[,3]))

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-18
    • 2021-08-07
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多