r - R 中的比例树形图

标签 r graph tree

我需要构建一个算法,给定一个由 n 个因素组成的 data.frame,返回一个树形图,其中每个节点代表一个因素的级别以及按该因素分类的行的比例该因子的级别以及上层节点的级别(例如,每个节点可以显示:factorX.levelY=30%)。

第一个节点将表示总行数,并将作为基数 (100)。树的第二层将有 k 个节点,对应于第一个因子的 k 个级别,第三层将有 k*m 个节点,其中 m 将是第二个因子的级别。等等。

用作函数输入的“data.frame”的列将以充当节点层次结构的方式排序。例如,data[,1] 将是树中的上层因子,data[,2] 等等。

以下是用作输入的 data.frame 示例:

 df<-data.frame( f1=factor( rep( LETTERS[1:2], each=50)),  
                 f2=rep( letters[1:4], each=25),
                 f3=rep( colors(1)[1:2], 25, each=2))

图表看起来像这样,但节点内的格式之前指出:(factorX.levelY=30%)

enter image description here

我注意到 rpart 包可以生成类似的图表,但函数接受的唯一输入是模型对象类型。

最佳答案

这是一种递归方法。首先,有一个函数来构建树结构,将每个分割级别的比例收集到一个命名的嵌套列表中。其次,有一个函数可以将嵌套列表转换为边缘列表以与 igraph 一起使用。最后,igraph 提供绘图功能。

## Create tree structure in nested list
makePtree <- function(data, prev=1) {
    tab <- (t <- table(data[,1L]))[t>0] / nrow(data)*prev                     # calculate proportions at current level
    ns <- sprintf("%s.%s=%.2f", names(data)[1L], names(tab), unname(c(tab)))  # names
    if (NCOL(data) < 2L) return( ns )                                         # we are done, return names only
    setNames(mapply(makePtree, split(data[,-1L,drop=F], data[,1L], drop=T),
                    tab, SIMPLIFY = F), ns)                                   # recurse
}

## Create edgelist from nested list for igraph::graph_from_data_frame
lst2edge <- function(lst) {
    if (!is.list(lst)) return( data.frame(a=character(0), b=character(0)) )
    do.call(rbind,
            c(lapply(names(lst), function(x) {
                if (!is.list(lst[[x]])) return( data.frame(a=x, b=lst[[x]]) )
                data.frame(a=x, b=names(lst[[x]]))
            }), lapply(lst, lst2edge)))
}

## Apply functions
lst <- makePtree(df)                                   # nested list
dat <- lst2edge(lst)                                   # edgelist
dat <- rbind(dat, data.frame(a="root", b=names(lst)))  # add a root node 

## Make an igraph
library(igraph)
g <- graph_from_data_frame(dat)
plot(g, layout=layout.reingold.tilford(g, root="root"))

enter image description here

如果您希望单独表示最终节点,您可以更改它们的名称,以便 igraph 分别指向它们。在这里,我修改了 lst2edge 函数,为最终关卡生成更长的名称。然后使用一些正则表达式来缩短它们以获得最终的数字。

## Create edgelist from nested list for igraph::graph_from_data_frame
lst2edge <- function(lst) {
    if (!is.list(lst)) return( data.frame(a=character(0), b=character(0)) )
    do.call(rbind,
            c(lapply(names(lst), function(x) {
                if (!is.list(lst[[x]])) return( data.frame(a=x, b=paste0(x, lst[[x]])) )
                data.frame(a=x, b=names(lst[[x]]))
            }), lapply(lst, lst2edge)))
}

## Apply functions
lst <- makePtree(df)                                           # nested list
dat <- lst2edge(lst)                                           # edgelist
dat <- rbind(dat, data.frame(a="root", b=names(lst)))          # add a root node 

## Make an igraph
g <- graph_from_data_frame(dat)

## Fix the names of the last level (they are lengthened in lst2edge
## so igraph doesn't show multiple incoming arrows to single nodes)
V(g)$name <- gsub(".*?([^\\.]+=[^=]+$)", "\\1", V(g)$name)
plot(g, layout=layout.reingold.tilford(g, root="root"),
     vertex.label.dist=-0.1, vertex.label.degree=c(rep(pi/2, 7), rep(c(pi/2, 3*pi/2), 4)))

enter image description here

您可以使用绘图函数的 vertex.label. Degree 参数调整顶点标签的位置。

关于r - R 中的比例树形图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32033835/

相关文章:

R Plotly 两个并排的图

r - 如何在 fitdistrplus 中使用尺度和位置参数拟合 t 分布

r - 如何使用变量的输出调用 R 中的向量

python-2.7 - 通过两个属性从列表聚类相关项目构建图形的更好方法

java - 使用 BSON 和 Java 构建树结构

python - 如何根据组中的其他实例对实例进行分类?

Python:继承内置类型

python - 图表中不显示任何点

python - Python GUI 中的文本树

树中序遍历 LISP