Wie kann man einen Beispielbaum aus randomForest :: getTree () zeichnen? [geschlossen]

62

Jeder hat Bibliotheks- oder Codevorschläge, wie man tatsächlich ein paar Beispielbäume plottet :

getTree(rfobj, k, labelVar=TRUE)

(Ja, ich weiß, Sie sollten dies nicht operativ tun, RF ist eine Blackbox usw. usw. Ich möchte einen Baum visuell auf Fehler überprüfen, um festzustellen, ob sich Variablen nicht intuitiv verhalten Wie gut funktionieren meine kodierten Faktoren usw.)


Vorherige Fragen ohne angemessene Antwort:

Eigentlich möchte ich einen Beispielbaum zeichnen . Also streiten Sie sich schon jetzt nicht mit mir darüber. Ich frage nicht nach varImpPlot(Variable Wichtigkeit Plot) oder partialPlotoder MDSPlotoder diesen anderen Plots , ich habe diese bereits, aber sie sind kein Ersatz für das Anzeigen eines Beispielbaums. Ja, ich kann die Ausgabe von visuell überprüfen getTree(...,labelVar=TRUE).

(Ich denke, ein plot.rf.tree()Beitrag würde sehr gut angenommen werden.)

smci
quelle
6
Ich sehe keinen Grund, präventiv zu argumentieren, besonders wenn Sie jemanden bitten, sich freiwillig zu melden, um Ihnen zu helfen. es kommt nicht gut rüber. CV hat eine Etikette-Richtlinie - vielleicht möchten Sie unsere FAQ lesen .
gung - Wiedereinsetzung von Monica
9
@gung: Jede frühere Frage zu diesem Thema ist in Menschen zerfallen, die darauf bestanden, dass es nicht notwendig und in der Tat ketzerisch war, einen Musterbaum zu zeichnen. Lesen Sie die Zitate, die ich gegeben habe. Ich suche nach einer Skizze, wie man einen RF-Baum zeichnet.
smci
3
Ich sehe einige Antworten, bei denen Benutzer versuchen, hilfreich zu sein und die Frage zu beantworten, sowie einige Kommentare, die die Prämisse der Idee in Frage stellen (die meiner Meinung nach auch hilfreich sein sollen). Es ist sicherlich möglich anzuerkennen, dass einige Leute anderer Meinung sind, wenn sie nicht gereizt sind.
gung - Wiedereinsetzung von Monica
4
Ich sehe in über einem Jahr keine Antworten, wo jemals jemand einen Baum gezeichnet hat. Ich suche nach einer konkreten Antwort auf diese konkrete Frage.
smci
1
Es ist möglich, einen einzelnen Baum zu zeichnen, mit dem cforest(im Party- Paket) gebaut wurde. Andernfalls müssen Sie das von data.framezurückgegebene Objekt randomForest::getTreein ein treeähnliches Objekt konvertieren .
Chl

Antworten:

44

Erste (und einfachste) Lösung: Wenn Sie sich nicht an die klassische RF halten möchten, wie sie in Andy Liaw implementiert ist randomForest, können Sie das Party- Paket ausprobieren , das eine andere Implementierung des ursprünglichen RF -Algorithmus bietet (Verwendung von bedingten Bäumen und Aggregationsschema basierend) nach Gewichtseinheiten (Durchschnittsgewicht). Dann können Sie, wie in diesem R-Hilfe-Beitrag berichtet , ein einzelnes Mitglied der Baumliste zeichnen. Es scheint reibungslos zu laufen, soweit ich das beurteilen kann. Unten sehen Sie eine grafische Darstellung eines Baumes, der von erstellt wurde cforest(Species ~ ., data=iris, controls=cforest_control(mtry=2, mincriterion=0)).

Bildbeschreibung hier eingeben

Zweitens (fast so einfach) Lösung: Die meisten Baum-basierte Techniken in R ( tree, rpart, TWIX, etc.) bietet eine tree-ähnlichen Struktur für den Druck / einen einzigen Baum Plotten. Die Idee wäre, die Ausgabe von randomForest::getTreein ein solches R-Objekt umzuwandeln , auch wenn es statistisch unsinnig ist. Grundsätzlich ist es einfach, von einem treeObjekt aus auf die Baumstruktur zuzugreifen , wie unten gezeigt. Bitte beachten Sie, dass es je nach Aufgabentyp - Regression oder Klassifizierung - geringfügige Unterschiede gibt. Im späteren Fall werden klassenspezifische Wahrscheinlichkeiten als letzte Spalte von obj$frame(das ist a data.frame) hinzugefügt .

> library(tree)
> tr <- tree(Species ~ ., data=iris)
> tr
node), split, n, deviance, yval, (yprob)
      * denotes terminal node

 1) root 150 329.600 setosa ( 0.33333 0.33333 0.33333 )  
   2) Petal.Length < 2.45 50   0.000 setosa ( 1.00000 0.00000 0.00000 ) *
   3) Petal.Length > 2.45 100 138.600 versicolor ( 0.00000 0.50000 0.50000 )  
     6) Petal.Width < 1.75 54  33.320 versicolor ( 0.00000 0.90741 0.09259 )  
      12) Petal.Length < 4.95 48   9.721 versicolor ( 0.00000 0.97917 0.02083 )  
        24) Sepal.Length < 5.15 5   5.004 versicolor ( 0.00000 0.80000 0.20000 ) *
        25) Sepal.Length > 5.15 43   0.000 versicolor ( 0.00000 1.00000 0.00000 ) *
      13) Petal.Length > 4.95 6   7.638 virginica ( 0.00000 0.33333 0.66667 ) *
     7) Petal.Width > 1.75 46   9.635 virginica ( 0.00000 0.02174 0.97826 )  
      14) Petal.Length < 4.95 6   5.407 virginica ( 0.00000 0.16667 0.83333 ) *
      15) Petal.Length > 4.95 40   0.000 virginica ( 0.00000 0.00000 1.00000 ) *
> tr$frame
            var   n        dev       yval splits.cutleft splits.cutright yprob.setosa yprob.versicolor yprob.virginica
1  Petal.Length 150 329.583687     setosa          <2.45           >2.45   0.33333333       0.33333333      0.33333333
2        <leaf>  50   0.000000     setosa                                  1.00000000       0.00000000      0.00000000
3   Petal.Width 100 138.629436 versicolor          <1.75           >1.75   0.00000000       0.50000000      0.50000000
6  Petal.Length  54  33.317509 versicolor          <4.95           >4.95   0.00000000       0.90740741      0.09259259
12 Sepal.Length  48   9.721422 versicolor          <5.15           >5.15   0.00000000       0.97916667      0.02083333
24       <leaf>   5   5.004024 versicolor                                  0.00000000       0.80000000      0.20000000
25       <leaf>  43   0.000000 versicolor                                  0.00000000       1.00000000      0.00000000
13       <leaf>   6   7.638170  virginica                                  0.00000000       0.33333333      0.66666667
7  Petal.Length  46   9.635384  virginica          <4.95           >4.95   0.00000000       0.02173913      0.97826087
14       <leaf>   6   5.406735  virginica                                  0.00000000       0.16666667      0.83333333
15       <leaf>  40   0.000000  virginica                                  0.00000000       0.00000000      1.00000000

Dann gibt es Methoden zum hübschen Drucken und Plotten dieser Objekte. Die Schlüsselfunktionen sind eine allgemeine tree:::plot.treeMethode (ich habe ein Triple angegeben :, mit der Sie den Code in R direkt tree:::treeplanzeigen können), die sich auf (grafische Anzeige) und tree:::treeco(Berechnung der Knotenkoordinaten ) stützt . Diese Funktionen erwarten die obj$frameDarstellung des Baumes. Andere subtile Probleme: (1) Das Argument type = c("proportional", "uniform")in der Standardplotmethode tree:::plot.treehilft, den vertikalen Abstand zwischen Knoten zu verwalten ( proportionalbedeutet, dass es proportional zur Abweichung ist, dh, uniformes ist fest). (2) Sie müssen plot(tr)durch einen Aufruf zum text(tr)Hinzufügen von Textbezeichnungen zu Knoten und Teilungen ergänzen, was in diesem Fall bedeutet, dass Sie auch einen Blick darauf werfen müssen tree:::text.tree.

Die getTreeMethode from randomForestgibt eine andere Struktur zurück, die in der Online-Hilfe dokumentiert ist. Unten ist eine typische Ausgabe dargestellt, bei der die Endknoten durch den statusCode (-1) gekennzeichnet sind. (Die Ausgabe unterscheidet sich wiederum je nach Aufgabentyp, jedoch nur nach den Spalten statusund prediction.)

> library(randomForest)
> rf <- randomForest(Species ~ ., data=iris)
> getTree(rf, 1, labelVar=TRUE)
   left daughter right daughter    split var split point status prediction
1              2              3 Petal.Length        4.75      1       <NA>
2              4              5 Sepal.Length        5.45      1       <NA>
3              6              7  Sepal.Width        3.15      1       <NA>
4              8              9  Petal.Width        0.80      1       <NA>
5             10             11  Sepal.Width        3.60      1       <NA>
6              0              0         <NA>        0.00     -1  virginica
7             12             13  Petal.Width        1.90      1       <NA>
8              0              0         <NA>        0.00     -1     setosa
9             14             15  Petal.Width        1.55      1       <NA>
10             0              0         <NA>        0.00     -1 versicolor
11             0              0         <NA>        0.00     -1     setosa
12            16             17 Petal.Length        5.40      1       <NA>
13             0              0         <NA>        0.00     -1  virginica
14             0              0         <NA>        0.00     -1 versicolor
15             0              0         <NA>        0.00     -1  virginica
16             0              0         <NA>        0.00     -1 versicolor
17             0              0         <NA>        0.00     -1  virginica

Wenn Sie es schaffen, die obige Tabelle zu dem konvertieren , erzeugt durch tree, werden Sie wahrscheinlich in der Lage sein , zu gestalten tree:::treepl, tree:::treecound an tree:::text.treeIhren Bedürfnissen anpassen, obwohl ich kein Beispiel für diesen Ansatz hat. Insbesondere möchten Sie wahrscheinlich die Verwendung von Abweichungen, Klassenwahrscheinlichkeiten usw. vermeiden, die in RF nicht von Bedeutung sind. Sie möchten lediglich Knotenkoordinaten einrichten und Werte teilen. Sie könnten das gebrauchen fixInNamespace(), aber um ehrlich zu sein, bin ich mir nicht sicher, ob dies der richtige Weg ist.

Dritte (und sicherlich clevere) Lösung: Schreiben Sie eine echte as.treeHilfsfunktion, die alle oben genannten "Patches" lindert. Sie könnten dann die Plotmethoden von R verwenden oder, wahrscheinlich besser, Klimt (direkt von R), um einzelne Bäume anzuzeigen.

chl
quelle
40

Ich bin vier Jahre zu spät, aber wenn Sie sich wirklich an das randomForestPaket halten möchten (und es gibt einige gute Gründe dafür) und den Baum tatsächlich visualisieren möchten, können Sie das reprtree- Paket verwenden.

Das Paket ist nicht sehr gut dokumentiert (die Dokumente finden Sie hier ), aber alles ist ziemlich einfach. Um das Paket zu installieren, beziehen Sie sich auf initialize.R im Repository. Führen Sie einfach Folgendes aus:

options(repos='http://cran.rstudio.org')
have.packages <- installed.packages()
cran.packages <- c('devtools','plotrix','randomForest','tree')
to.install <- setdiff(cran.packages, have.packages[,1])
if(length(to.install)>0) install.packages(to.install)

library(devtools)
if(!('reprtree' %in% installed.packages())){
  install_github('araastat/reprtree')
}
for(p in c(cran.packages, 'reprtree')) eval(substitute(library(pkg), list(pkg=p)))

Dann machen Sie Ihr Modell und Ihren Baum:

library(randomForest)
library(reprtree)

model <- randomForest(Species ~ ., data=iris, importance=TRUE, ntree=500, mtry = 2, do.trace=100)

reprtree:::plot.getTree(model)

Und los geht's! Schön und einfach.

Baum generiert aus plot.getTree (Modell)

Sie können das Github-Repo überprüfen, um mehr über die anderen Methoden im Paket zu erfahren. In der Tat, wenn Sie plot.getTree.R überprüfen , werden Sie feststellen, dass der Autor seine eigene Implementierung verwendet, von as.tree()der chl ♦ vorschlug, dass Sie sich selbst in seine Antwort einbauen könnten. Dies bedeutet, dass Sie dies tun können:

tree <- getTree(model, k=1, labelVar=TRUE)
realtree <- reprtree:::as.tree(tree, model)

Und dann möglicherweise realtreemit anderen Tree-Plotting-Paketen wie tree verwenden .

jgozal
quelle
Vielen Dank, ich nehme immer noch gerne Antworten entgegen. Dies scheint ein Bereich zu sein, in dem die Menschen mit den Angeboten unzufrieden sind. Ich denke, die neue Sache wäre auch zu unterstützen xgboost.
SMCI
6
kein Problem. Es hat Stunden gedauert, bis ich die Bibliothek / das Paket gefunden habe, also dachte ich mir, wenn es für Sie nicht nützlich ist, würden es andere Menschen sein, die versuchen, Bäume zu malen, während sie immer noch am randomForestPaket festhalten .
Jgozal
2
Coole Entdeckung. Anmerkung: Es wird der repräsentative Baum in gewisser Weise gezeichnet, der Baum im Ensemble, der im Durchschnitt allen anderen Bäumen im Ensemble "am nächsten" liegt
Chris,
2
@Chris Die Funktion plot.getTree()zeichnet einen einzelnen Baum. Die Funktion plot.reprtree()in diesem Paket zeichnet einen repräsentativen Baum.
Chun Li
1
Ich habe ein Modell von Caret und möchte es in Reptree einspeisen. Es reprtree:::plot.getTree(mod_rf_1$finalModel)gibt jedoch einen "Fehler in data.frame" (var = fr $ var, splits = as.character (gTree [, "split point"]) Anzahl der Zeilen: 2631, 0 "
HappyCoding
15

Ich habe einige Funktionen erstellt, um die Regeln eines Baums zu extrahieren.

#**************************
#return the rules of a tree
#**************************
getConds<-function(tree){
  #store all conditions into a list
  conds<-list()
  #start by the terminal nodes and find previous conditions
  id.leafs<-which(tree$status==-1)
	  j<-0
	  for(i in id.leafs){
		j<-j+1
		prevConds<-prevCond(tree,i)
		conds[[j]]<-prevConds$cond
		while(prevConds$id>1){
		  prevConds<-prevCond(tree,prevConds$id)
		  conds[[j]]<-paste(conds[[j]]," & ",prevConds$cond)
        }
		if(prevConds$id==1){
			conds[[j]]<-paste(conds[[j]]," => ",tree$prediction[i])
    }
    }

  }

  return(conds)
}

#**************************
#find the previous conditions in the tree
#**************************
prevCond<-function(tree,i){
  if(i %in% tree$right_daughter){
		id<-which(tree$right_daughter==i)
		cond<-paste(tree$split_var[id],">",tree$split_point[id])
	  }
	  if(i %in% tree$left_daughter){
    id<-which(tree$left_daughter==i)
		cond<-paste(tree$split_var[id],"<",tree$split_point[id])
  }

  return(list(cond=cond,id=id))
}

#remove spaces in a word
collapse<-function(x){
  x<-sub(" ","_",x)

  return(x)
}


data(iris)
require(randomForest)
mod.rf <- randomForest(Species ~ ., data=iris)
tree<-getTree(mod.rf, k=1, labelVar=TRUE)
#rename the name of the column
colnames(tree)<-sapply(colnames(tree),collapse)
rules<-getConds(tree)
print(rules)
Dalpozz
quelle