【问题标题】:Rotate Classification Tree Terminal Barplot axis - R旋转分类树终端条形图轴 - R
【发布时间】:2012-08-11 07:30:15
【问题描述】:

我有一个使用ctree() 分析的分类树,想知道如何旋转终端节点以使轴垂直?

library(party)
data(iris)
attach(iris)
plot(ctree(Species ~ Sepal.Length + Sepel.Width 
     + Petal.Length + Petal.Width, data = iris))

【问题讨论】:

    标签: r statistics decision-tree party


    【解决方案1】:

    这就是我的做法。不是最短的答案,但我想尽可能彻底。

    由于我们正在绘制您的树,因此最好查看文档以了解适当的绘图功能:

    library(party)
    data(iris)
    attach(iris)
    
    ctree <- ctree(Species ~ Sepal.Length + Sepal.Width 
                   + Petal.Length + Petal.Width, data = iris)
    
    # getting ctree's class
    
    > class(ctree)
    [1] "BinaryTree"
    attr(,"package")
    [1] "party"
    

    查看?'plot.BinaryTree',我们看到terminal_panel参数的以下描述:

    一个可选的面板函数,形式为function(node) 绘制终端节点。或者,面板生成 使用参数 x 调用的类“grapcon_generator”的函数 和 tp_args 设置面板功能。默认情况下,适当的 面板函数的选择取决于依赖的规模 变量。

    文档的更下方是指向?node_barplot 的链接。这就是我猜想被用作默认值的东西,调用以下证明是正确的:

    plot(ctree, terminal_panel = node_barplot(ctree))
    

    (输出与您的原始图表相同)。

    很遗憾,node_barplot 没有 horizontalhoriz 参数。查看此函数的代码,只需在提示符处键入node_barplot,就会发现图形是使用视口“手动”绘制的。不幸的是,我能找到的唯一方法是编辑这个函数。我试图使我的更改尽可能明显:

    # Note inclusion of horiz = FALSE
    alt_node_barplot <- function (ctreeobj, col = "black", fill = NULL, beside = NULL, 
        ymax = NULL, ylines = NULL, widths = 1, gap = NULL, reverse = NULL, 
        id = TRUE, horiz = FALSE)
    {
        getMaxPred <- function(x) {
            mp <- max(x$prediction)
            mpl <- ifelse(x$terminal, 0, getMaxPred(x$left))
            mpr <- ifelse(x$terminal, 0, getMaxPred(x$right))
            return(max(c(mp, mpl, mpr)))
        }
        y <- response(ctreeobj)[[1]]
        if (is.factor(y) || class(y) == "was_ordered") {
            ylevels <- levels(y)
            if (is.null(beside)) 
                beside <- if (length(ylevels) < 3) 
                    FALSE
                else TRUE
            if (is.null(ymax)) 
                ymax <- if (beside) 
                    1.1
                else 1
            if (is.null(gap)) 
                gap <- if (beside) 
                    0.1
                else 0
        }
        else {
            if (is.null(beside)) 
                beside <- FALSE
            if (is.null(ymax)) 
                ymax <- getMaxPred(ctreeobj@tree) * 1.1
            ylevels <- seq(along = ctreeobj@tree$prediction)
            if (length(ylevels) < 2) 
                ylevels <- ""
            if (is.null(gap)) 
                gap <- 1
        }
        if (is.null(reverse)) 
            reverse <- !beside
        if (is.null(fill)) 
            fill <- gray.colors(length(ylevels))
        if (is.null(ylines)) 
            ylines <- if (beside) 
                c(3, 2)
            else c(1.5, 2.5)
        # My edit do not work if beside is not true
        #################################################
        if(!beside) horiz = FALSE
        #################################################
    
        rval <- function(node) {
            pred <- node$prediction
            if (reverse) {
                pred <- rev(pred)
                ylevels <- rev(ylevels)
            }
            np <- length(pred)
            nc <- if (beside) 
                np
            else 1
            fill <- rep(fill, length.out = np)
            widths <- rep(widths, length.out = nc)
            col <- rep(col, length.out = nc)
            ylines <- rep(ylines, length.out = 2)
            gap <- gap * sum(widths)
            #######################################################
            if (!horiz){
                yscale <- c(0, ymax)
                xscale <- c(0, sum(widths) + (nc + 1) * gap)
            } else {
                xscale <- c(0, ymax)
                yscale <- c(0, sum(widths) + (nc + 1) * gap)
            }                    
            #######################################################
            top_vp <- viewport(layout = grid.layout(nrow = 2, ncol = 3, 
                widths = unit(c(ylines[1], 1, ylines[2]), c("lines", 
                    "null", "lines")), heights = unit(c(1, 1), c("lines", 
                    "null"))), width = unit(1, "npc"), height = unit(1, 
                "npc") - unit(2, "lines"), name = paste("node_barplot", 
                node$nodeID, sep = ""))
            pushViewport(top_vp)
            grid.rect(gp = gpar(fill = "white", col = 0))
            top <- viewport(layout.pos.col = 2, layout.pos.row = 1)
            pushViewport(top)
            mainlab <- paste(ifelse(id, paste("Node", node$nodeID, 
                "(n = "), "n = "), sum(node$weights), ifelse(id, 
                ")", ""), sep = "")
            grid.text(mainlab)
            popViewport()
            plot <- viewport(layout.pos.col = 2, layout.pos.row = 2, 
                xscale = xscale, yscale = yscale, name = paste("node_barplot", 
                    node$nodeID, "plot", sep = ""))
            pushViewport(plot)
            if (beside) {
                #############################################################
                if(!horiz){
                    xcenter <- cumsum(widths + gap) - widths/2
                    for (i in 1:np) {
                        grid.rect(x = xcenter[i], y = 0, height = pred[i], 
                          width = widths[i], just = c("center", "bottom"), 
                          default.units = "native", gp = gpar(col = col[i], 
                            fill = fill[i]))
                    }
                    if (length(xcenter) > 1) 
                        grid.xaxis(at = xcenter, label = FALSE)
                    grid.text(ylevels, x = xcenter, y = unit(-1, "lines"), 
                        just = c("center", "top"), default.units = "native", 
                        check.overlap = TRUE)
                    grid.yaxis()
                } else {
                    ycenter <- cumsum(widths + gap) - widths/2
                    for (i in 1:np) {
                        grid.rect(y = ycenter[i], x = 0, width = pred[i], 
                        height = widths[i], just = c("left", "center"), 
                        default.units = "native", gp = gpar(col = col[i], 
                         fill = fill[i]))
                    }
                    if (length(ycenter) > 1) 
                        grid.yaxis(at = ycenter, label = FALSE)
                            grid.text(ylevels, y = ycenter, x = unit(-1, "lines"), 
                            just = c("right", "center"), default.units = "native", 
                             check.overlap = TRUE)
                    grid.xaxis()
                }
            #############################################################
            }
            else {
                ycenter <- cumsum(pred) - pred
                for (i in 1:np) {
                    grid.rect(x = xscale[2]/2, y = ycenter[i], height = min(pred[i], 
                      ymax - ycenter[i]), width = widths[1], just = c("center", 
                      "bottom"), default.units = "native", gp = gpar(col = col[i], 
                      fill = fill[i]))
                }
                if (np > 1) {
                    grid.text(ylevels[1], x = unit(-1, "lines"), 
                      y = 0, just = c("left", "center"), rot = 90, 
                      default.units = "native", check.overlap = TRUE)
                    grid.text(ylevels[np], x = unit(-1, "lines"), 
                      y = ymax, just = c("right", "center"), rot = 90, 
                      default.units = "native", check.overlap = TRUE)
                }
                if (np > 2) {
                    grid.text(ylevels[-c(1, np)], x = unit(-1, "lines"), 
                      y = ycenter[-c(1, np)], just = "center", rot = 90, 
                      default.units = "native", check.overlap = TRUE)
                }
                grid.yaxis(main = FALSE)
            }
            grid.rect(gp = gpar(fill = "transparent"))
            upViewport(2)
        }
        return(rval)
    }
    

    现在我们可以测试它了!

    plot(ctree, terminal_panel = alt_node_barplot(ctree, horiz = TRUE))
    

    这是输出:

    只有几点:

    • 我承认这可能不是您问题的解决方案。当没有更简单的选择时,这只是解决此类问题的一种方法。

    • 不要完全相信我上面给出的函数。如您所见,beside 参数自动禁用horiz 参数(我的第一次编辑),因为我没有更改处理beside 的代码部分为真。如果您希望它在这种情况下工作,您必须自己进行这些编辑 - 请查看 ?viewport?grid.rect 以开始使用。我很确定 reverse 函数也坏了,但没有测试任何东西。如果我稍微扼杀了它,请向该函数的原始作者道歉,这只是一个演示。

    我希望这会有所帮助。祝您好运,您需要进行任何进一步的编辑!

    【讨论】:

      猜你喜欢
      • 2014-07-07
      • 2017-06-24
      • 2012-05-04
      • 2013-12-13
      • 1970-01-01
      • 2017-07-01
      • 2017-08-30
      相关资源
      最近更新 更多