如何在R中绘制/可视化C50决策树?

9

我正在使用C50决策树算法。我能够构建树并得到摘要,但无法弄清楚如何绘制或可视化树。

我的C50模型名为credit_model

在其他决策树包中,我通常使用类似于plot(credit_model)的命令。在rpart中,是rpart.plot(credit_model)。

在C50算法中,相当于plot的命令是什么?


2
目前(2015-08-07),C5.0具有绘图功能。 - user989762
这个问题更适合在[可视化C5.0决策树]讨论(http://stats.stackexchange.com/questions/198134/visualizing-c5-0-decision-tree),而且这里的所有回答都已经过时了,因为现在有了绘图函数。 - smci
3个回答

1
这是您正在寻找的函数:

C5.0.graphviz <- function( C5.0.model, filename, fontname ='Arial',col.draw ='black',
                           col.font ='blue',col.conclusion ='lightpink',col.question = 'grey78',
                           shape.conclusion ='box3d',shape.question ='diamond', 
                           bool.substitute = 'None', prefix=FALSE, vertical=TRUE ) {

  library(cwhmisc)  
  library(stringr) 
  treeout <- C5.0.model$output
  treeout<- substr(treeout, cpos(treeout, 'Decision tree:', start=1)+14,nchar(treeout))
  treeout<- substr(treeout, 1,cpos(treeout, 'Evaluation on training data', start=1)-2)
  variables <- data.frame(matrix(nrow=500, ncol=4)) 
  names(variables) <- c('SYMBOL','TOKEN', 'TYPE' , 'QUERY') 
  connectors <- data.frame(matrix(nrow=500, ncol=3)) 
  names(connectors) <- c('TOKEN', 'START','END')
  theStack <- data.frame(matrix(nrow=500, ncol=1)) 
  names(theStack) <- c('ITEM')
  theStackIndex <- 1
  currentvar <- 1
  currentcon <- 1
  open_connection <- TRUE
  previousindent <- -1
  firstindent <- 4
  substitutes <- data.frame(None=c('= 0','= 1'), yesno=c('no','yes'),
                            truefalse=c('false', 'true'),TF=c('F','T'))
  dtreestring<-unlist( scan(text= treeout,   sep='\n', what =list('character'))) 

  for (linecount in c(1:length(dtreestring))) {
    lineindent<-0
    shortstring <- str_trim(dtreestring[linecount], side='left')
    leadingspaces <- nchar(dtreestring[linecount]) - nchar(shortstring)
    lineindent <- leadingspaces/4
    dtreestring[linecount]<-str_trim(dtreestring[linecount], side='left') 
    while (!is.na(cpos(dtreestring[linecount], ':   ', start=1)) ) {
      lineindent<-lineindent + 1 
      dtreestring[linecount]<-substr(dtreestring[linecount],
                                     ifelse(is.na(cpos(dtreestring[linecount], ':   ', start=1)), 1,
                                            cpos(dtreestring[linecount], ':   ', start=1)+4),
                                     nchar(dtreestring[linecount]) )
      shortstring <- str_trim(dtreestring[linecount], side='left')
      leadingspaces <- nchar(dtreestring[linecount]) - nchar(shortstring)
      lineindent <- lineindent + leadingspaces/4
      dtreestring[linecount]<-str_trim(dtreestring[linecount], side='left')  
    }
    if (!is.na(cpos(dtreestring[linecount], ':...', start=1)))
      lineindent<- lineindent +  1 
    dtreestring[linecount]<-substr(dtreestring[linecount],
                                   ifelse(is.na(cpos(dtreestring[linecount], ':...', start=1)), 1,
                                          cpos(dtreestring[linecount], ':...', start=1)+4),
                                   nchar(dtreestring[linecount]) )
    dtreestring[linecount]<-str_trim(dtreestring[linecount])
    stringlist <- strsplit(dtreestring[linecount],'\\:')
    stringpart <- strsplit(unlist(stringlist)[1],'\\s')
    if (open_connection==TRUE) { 
      variables[currentvar,'TOKEN'] <- unlist(stringpart)[1]
      variables[currentvar,'SYMBOL'] <- paste('node',as.character(currentvar), sep='')
      variables[currentvar,'TYPE'] <- shape.question
      variables[currentvar,'QUERY'] <- 1
      theStack[theStackIndex,'ITEM']<-variables[currentvar,'SYMBOL']
      theStack[theStackIndex,'INDENT'] <-firstindent 
      theStackIndex<-theStackIndex+1
      currentvar <- currentvar + 1
      if(currentvar>2) { 
        connectors[currentcon - 1,'END'] <- variables[currentvar - 1, 'SYMBOL']
      }
    }
    connectors[currentcon,'TOKEN'] <- paste(unlist(stringpart)[2],unlist(stringpart)[3])
    if (connectors[currentcon,'TOKEN']=='= 0') 
      connectors[currentcon,'TOKEN'] <- as.character(substitutes[1,bool.substitute])
    if (connectors[currentcon,'TOKEN']=='= 1') 
      connectors[currentcon,'TOKEN'] <- as.character(substitutes[2,bool.substitute])
    if (open_connection==TRUE) { 
      if (lineindent<previousindent) {
        theStackIndex <- theStackIndex-(( previousindent- lineindent)  +1 )
        currentsymbol <-theStack[theStackIndex,'ITEM']
      } else 
        currentsymbol <-variables[currentvar - 1,'SYMBOL']
    } else {  
      currentsymbol <-theStack[theStackIndex-((previousindent -lineindent ) +1    ),'ITEM']
      theStackIndex <- theStackIndex-(( previousindent- lineindent)    )
    }
    connectors[currentcon, 'START'] <- currentsymbol
    currentcon <- currentcon + 1
    open_connection <- TRUE 
    if (length(unlist(stringlist))==2) {
      stringpart2 <- strsplit(unlist(stringlist)[2],'\\s')
      variables[currentvar,'TOKEN']  <- paste(ifelse((prefix==FALSE),'','Class'), unlist(stringpart2)[2]) 
      variables[currentvar,'SYMBOL']  <- paste('node',as.character(currentvar), sep='')
      variables[currentvar,'TYPE']   <- shape.conclusion
      variables[currentvar,'QUERY']  <- 0
      currentvar <- currentvar + 1
      connectors[currentcon - 1,'END'] <- variables[currentvar - 1,'SYMBOL']
      open_connection <- FALSE
    }
    previousindent<-lineindent
  }
  runningstring <- paste('digraph g {', 'graph ', sep='\n')
  runningstring <- paste(runningstring, ' [rankdir="', sep='')
  runningstring <- paste(runningstring, ifelse(vertical==TRUE,'TB','LR'), sep='' )
  runningstring <- paste(runningstring, '"]', sep='')
  for (lines in c(1:(currentvar-1))) {
    runningline <- paste(variables[lines,'SYMBOL'], '[shape="')
    runningline <- paste(runningline,variables[lines,'TYPE'], sep='' )
    runningline <- paste(runningline,'" label ="', sep='' )
    runningline <- paste(runningline,variables[lines,'TOKEN'], sep='' )
    runningline <- paste(runningline,
                         '" style=filled fontcolor=', sep='')
    runningline <- paste(runningline, col.font)
    runningline <- paste(runningline,' color=' )
    runningline <- paste(runningline, col.draw)
    runningline <- paste(runningline,' fontname=')
    runningline <- paste(runningline, fontname)
    runningline <- paste(runningline,' fillcolor=')
    runningline <- paste(runningline,
                         ifelse(variables[lines,'QUERY']== 0 ,col.conclusion,col.question))
    runningline <- paste(runningline,'];')
    runningstring <- paste(runningstring, runningline , sep='\n')
  }
  for (lines in c(1:(currentcon-1)))  { 
    runningline <- paste (connectors[lines,'START'], '->')
    runningline <- paste (runningline, connectors[lines,'END'])
    runningline <- paste (runningline,'[label="')
    runningline <- paste (runningline,connectors[lines,'TOKEN'], sep='')
    runningline <- paste (runningline,'" fontname=', sep='')
    runningline <- paste (runningline, fontname)
    runningline <- paste (runningline,'];')
    runningstring <- paste(runningstring, runningline , sep='\n')
  }
  runningstring <- paste(runningstring,'}')
  cat(runningstring)
  sink(filename, split=TRUE)
  cat(runningstring)
  sink()
}

1
您可以使用以下程序,直接将决策树转换为GraphViz点语言(然后使用GraphViz绘制它 - 需要先安装GraphViz http://www.graphviz.org/)。 < p > < em >编辑:此处包含版本2,能够处理多分支树(版本1仅能处理具有两个分裂的树)。 版本2.2更正了缺少的初始化。

在R中调用示例:

library(C50)
data(churn)
treeModel <- C5.0(x = churnTrain[, -20], y = churnTrain$churn)
C5.0.graphviz(treeModel, 'C:\\mydotfile.txt')

然后从操作系统(OS,例如Windows命令提示符)开始:

dot -Tpng 'C:\mydotfile.txt' > 'C:\mygraph.png'

你可以打开mygraph.png文件作为PNG(位图),并在应用程序中使用它。
如需更多详细信息,请参阅原始帖子:http://r-project-thanos.blogspot.de/2014/09/plot-c50-decision-trees-in-r.html
   C5.0.graphviz <- function( C5.0.model,   filename, fontname ='Arial',
       col.draw ='black',col.font ='blue',col.conclusion ='lightpink',
       col.question = 'grey78', shape.conclusion ='box3d',shape.question ='diamond', 
       bool.substitute = 'None', prefix=FALSE, vertical=TRUE ) {

    library(cwhmisc)  
    library(stringr) 
    treeout <- C5.0.model$output
    treeout<- substr(treeout,   cpos(treeout, 'Decision tree:', start=1)+14,nchar(treeout))
    treeout<- substr(treeout,   1,cpos(treeout, 'Evaluation on training data', start=1)-2)
    variables <- data.frame(matrix(nrow=500, ncol=4)) 
    names(variables) <- c('SYMBOL','TOKEN', 'TYPE' , 'QUERY') 
    connectors <- data.frame(matrix(nrow=500, ncol=3)) 
    names(connectors) <- c('TOKEN', 'START','END')
    theStack <- data.frame(matrix(nrow=500, ncol=1)) 
    names(theStack) <- c('ITEM')
    theStackIndex <- 1
    currentvar <- 1
    currentcon <- 1
    open_connection <- TRUE
    previousindent <- -1
    firstindent <- 4
    substitutes <- data.frame(None=c('= 0','= 1'), yesno=c('no','yes'),
        truefalse=c('false', 'true'),TF=c('F','T'))
    dtreestring<-unlist( scan(text= treeout,   sep='\n', what =list('character')))  

    for (linecount in c(1:length(dtreestring))) {
        lineindent<-0
        shortstring <- str_trim(dtreestring[linecount], side='left')
        leadingspaces <- nchar(dtreestring[linecount]) - nchar(shortstring)
        lineindent <- leadingspaces/4
        dtreestring[linecount]<-str_trim(dtreestring[linecount], side='left') 
            while (!is.na(cpos(dtreestring[linecount], ':   ', start=1)) ) {
                        lineindent<-lineindent + 1 
                        dtreestring[linecount]<-substr(dtreestring[linecount],
                            ifelse(is.na(cpos(dtreestring[linecount], ':   ', start=1)), 1,
                            cpos(dtreestring[linecount], ':   ', start=1)+4),
                            nchar(dtreestring[linecount]) )
                        shortstring <- str_trim(dtreestring[linecount], side='left')
                        leadingspaces <- nchar(dtreestring[linecount]) - nchar(shortstring)
                        lineindent <- lineindent + leadingspaces/4
                        dtreestring[linecount]<-str_trim(dtreestring[linecount], side='left')   
            }
        if (!is.na(cpos(dtreestring[linecount], ':...', start=1)))
                lineindent<- lineindent +  1 
        dtreestring[linecount]<-substr(dtreestring[linecount],
                ifelse(is.na(cpos(dtreestring[linecount], ':...', start=1)), 1,
                cpos(dtreestring[linecount], ':...', start=1)+4),
                nchar(dtreestring[linecount]) )
        dtreestring[linecount]<-str_trim(dtreestring[linecount])
        stringlist <- strsplit(dtreestring[linecount],'\\:')
        stringpart <- strsplit(unlist(stringlist)[1],'\\s')
        if (open_connection==TRUE) { 
                    variables[currentvar,'TOKEN'] <- unlist(stringpart)[1]
                    variables[currentvar,'SYMBOL'] <- paste('node',as.character(currentvar), sep='')
                    variables[currentvar,'TYPE'] <- shape.question
                    variables[currentvar,'QUERY'] <- 1
                theStack[theStackIndex,'ITEM']<-variables[currentvar,'SYMBOL']
                    theStack[theStackIndex,'INDENT'] <-firstindent 
                    theStackIndex<-theStackIndex+1
                    currentvar <- currentvar + 1
                    if(currentvar>2) {  
                    connectors[currentcon - 1,'END'] <- variables[currentvar - 1, 'SYMBOL']
                    }
            }
        connectors[currentcon,'TOKEN'] <- paste(unlist(stringpart)[2],unlist(stringpart)[3])
        if (connectors[currentcon,'TOKEN']=='= 0') 
            connectors[currentcon,'TOKEN'] <- as.character(substitutes[1,bool.substitute])
        if (connectors[currentcon,'TOKEN']=='= 1') 
            connectors[currentcon,'TOKEN'] <- as.character(substitutes[2,bool.substitute])
        if (open_connection==TRUE) { 
                        if (lineindent<previousindent) {
                                theStackIndex <- theStackIndex-(( previousindent- lineindent)  +1 )
                                currentsymbol <-theStack[theStackIndex,'ITEM']
                        } else  
                            currentsymbol <-variables[currentvar - 1,'SYMBOL']
        } else {  
                        currentsymbol <-theStack[theStackIndex-((previousindent -lineindent ) +1    ),'ITEM']
                        theStackIndex <- theStackIndex-(( previousindent- lineindent)    )
        }
        connectors[currentcon, 'START'] <- currentsymbol
        currentcon <- currentcon + 1
        open_connection <- TRUE 
        if (length(unlist(stringlist))==2) {
              stringpart2 <- strsplit(unlist(stringlist)[2],'\\s')
                variables[currentvar,'TOKEN']   <- paste(ifelse((prefix==FALSE),'','Class'), unlist(stringpart2)[2]) 
                variables[currentvar,'SYMBOL']  <- paste('node',as.character(currentvar), sep='')
                variables[currentvar,'TYPE']        <- shape.conclusion
                variables[currentvar,'QUERY']   <- 0
                currentvar <- currentvar + 1
                connectors[currentcon - 1,'END'] <- variables[currentvar - 1,'SYMBOL']
            open_connection <- FALSE
        }
        previousindent<-lineindent
    }
    runningstring <- paste('digraph g {', 'graph ', sep='\n')
    runningstring <- paste(runningstring, ' [rankdir="', sep='')
    runningstring <- paste(runningstring, ifelse(vertical==TRUE,'TB','LR'), sep='' )
    runningstring <- paste(runningstring, '"]', sep='')
    for (lines in c(1:(currentvar-1))) {
        runningline <- paste(variables[lines,'SYMBOL'], '[shape="')
        runningline <- paste(runningline,variables[lines,'TYPE'], sep='' )
        runningline <- paste(runningline,'" label ="', sep='' )
        runningline <- paste(runningline,variables[lines,'TOKEN'], sep='' )
        runningline <- paste(runningline,
            '" style=filled fontcolor=', sep='')
        runningline <- paste(runningline, col.font)
        runningline <- paste(runningline,' color=' )
        runningline <- paste(runningline, col.draw)
        runningline <- paste(runningline,' fontname=')
        runningline <- paste(runningline, fontname)
        runningline <- paste(runningline,' fillcolor=')
        runningline <- paste(runningline,
            ifelse(variables[lines,'QUERY']== 0 ,col.conclusion,col.question))
        runningline <- paste(runningline,'];')
        runningstring <- paste(runningstring,   runningline , sep='\n')
    }
  for (lines in c(1:(currentcon-1)))        { 
    runningline <- paste (connectors[lines,'START'], '->')
    runningline <- paste (runningline, connectors[lines,'END'])
    runningline <- paste (runningline,'[label="')
    runningline <- paste (runningline,connectors[lines,'TOKEN'], sep='')
    runningline <- paste (runningline,'" fontname=', sep='')
    runningline <- paste (runningline, fontname)
    runningline <- paste (runningline,'];')
    runningstring <- paste(runningstring,   runningline , sep='\n')
  }
    runningstring <- paste(runningstring,'}')
    cat(runningstring)
    sink(filename, split=TRUE)
    cat(runningstring)
    sink()
}

灭霸


你如何在R中使用graphviz函数? - Cybernetic
你不需要使其可用。你可以从操作系统(Windows、Linux等)中调用Graphviz的dot命令。输入参数是由上面介绍的C5.0.graphviz函数生成的文本文件,dot命令的输出文件将是图形文件,可用于你的应用程序(Word等)。 - Thanos
我遇到了一个错误 dot: can't open 'mytree.txt',你有什么想法为什么会出现这个错误? - Furqan Hashim

1

目前还没有内置的内容。我一直在为partykit包(例如as.party)工作适配器,但并没有取得太大进展。

Max


2
现在已经有了,对于新来的人...它绘制树形图而不是基于规则的模型...顺便说一下:https://cran.r-project.org/web/packages/C50/C50.pdf - slushy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接