Как на самом деле построить образец дерева из randomForest :: getTree ()? [закрыто]


62

Кто-нибудь получил библиотеку или предложения кода о том, как на самом деле построить пару образцов деревьев из:

getTree(rfobj, k, labelVar=TRUE)

(Да, я знаю, что вы не должны делать это оперативно, RF - это черный ящик и т. Д. И т. Д. Я хочу визуально проверить работоспособность дерева, чтобы убедиться, что какие-то переменные ведут себя нелогично, нужно настроить / объединить / дискретизировать / преобразовать, проверить насколько хорошо работают мои закодированные факторы и т. д.)


Предыдущие вопросы без достойного ответа:

Я на самом деле хочу построить образец дерева . Так что не спорьте со мной об этом, уже. Я не спрашиваю о varImpPlot(График важности переменной) или partialPlotили MDSPlot, или эти другие графики , у меня уже есть, но они не являются заменой для просмотра образца дерева. Да, я могу визуально проверить вывод getTree(...,labelVar=TRUE).

(Я думаю, что plot.rf.tree()вклад был бы очень хорошо принят.)


6
Я не вижу необходимости превентивно спорить, особенно если вы просите кого-то добровольно помочь вам; это не очень хорошо. CV имеет правила этикета - вы можете прочитать наш FAQ .
gung - Восстановить Монику

9
@gung: каждый предыдущий вопрос по этой теме распался на людей, настаивающих на том, что нет необходимости и даже еретики строить образец дерева. Прочитайте цитаты, которые я дал. Я ищу эскиз того, как кодировать построение дерева RF.
smci

3
Я вижу некоторые ответы, где пользователи пытаются помочь и ответить на этот вопрос, а также некоторые комментарии, ставящие под сомнение предпосылку идеи (которые, я искренне верю, также предназначены для полезного духа). Конечно, можно признать, что некоторые люди не согласятся с тем, чтобы быть раздражительным.
gung - Восстановить Монику

4
Я вижу ноль ответов, где кто-нибудь когда-либо строил дерево за год. Я ищу конкретный ответ на этот конкретный вопрос.
smci

1
Можно построить одно построенное дерево cforest(в пакете для вечеринок ). В противном случае вам придется преобразовать data.frameвозвращаемый объект randomForest::getTreeв tree-подобный объект.
ЧЛ

Ответы:


44

Первое (и самое простое) решение: если вы не хотите придерживаться классической RF, как это реализовано в Andy Liaw randomForest, вы можете попробовать пакет party , который обеспечивает другую реализацию оригинального алгоритма RF (использование условных деревьев и схемы агрегации на основе на единицу веса средний). Затем, как сообщается в этом посте R-help , вы можете нанести на карту одного члена списка деревьев. Кажется, все идет гладко, насколько я могу судить. Ниже приведен график одного дерева, созданного cforest(Species ~ ., data=iris, controls=cforest_control(mtry=2, mincriterion=0)).

введите описание изображения здесь

Во- вторых (почти так же легко) Решение: Большинство методов дерева на основе в R ( tree, rpart, TWIXи т.д.) предлагает tree-like структуру для печати / прокладки одного дерева. Идея заключалась бы в том, чтобы преобразовать выходные данные randomForest::getTreeв такой объект R, даже если это бессмысленно со статистической точки зрения. По сути, легко получить доступ к древовидной структуре treeобъекта, как показано ниже. Обратите внимание, что он будет немного отличаться в зависимости от типа задачи - регрессия или классификация, - где в последнем случае он добавит специфичные для класса вероятности в качестве последнего столбца obj$frame(который является data.frame).

> 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

Затем есть методы для красивой печати и печати этих объектов. Ключевые функции - это общий tree:::plot.treeметод (я поставил тройку, :которая позволяет вам просматривать код в R напрямую), опираясь на tree:::treepl(графическое отображение) и tree:::treeco(вычисление координат узлов). Эти функции ожидают obj$frameпредставления дерева. Другие тонкие вопросы: (1) аргумент type = c("proportional", "uniform")в методе построения графиков по умолчанию, tree:::plot.treeпомогает управлять вертикальным расстоянием между узлами ( proportionalозначает, что оно пропорционально отклонению, uniformзначит, оно фиксировано); (2) вам нужно дополнить plot(tr)вызовом, чтобы text(tr)добавить текстовые метки к узлам и разбиениям, что в этом случае означает, что вам также придется взглянуть tree:::text.tree.

getTreeМетод из randomForestвозвращений другой структуры, которая описана в интерактивной справке. Типичный вывод показан ниже, с терминальными узлами, обозначенными statusкодом (-1). (Опять же , выход будет отличаться в зависимости от типа задачи, но только на statusи 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

Если вам удастся преобразовать таблицу выше в одной генерируемых tree, вы, вероятно , будете иметь возможность настроить tree:::treepl, tree:::treecoи tree:::text.treeв соответствии с вашими потребностями, хотя я не пример такого подхода. В частности, вы, вероятно, хотите избавиться от использования отклонений, вероятностей классов и т. Д., Которые не имеют смысла в РФ. Все, что вам нужно, это установить координаты узлов и разделить значения. Вы могли бы использовать fixInNamespace()это, но, честно говоря, я не уверен, что это правильный путь.

Третье (и, конечно, умное) решение: напишите настоящую as.treeвспомогательную функцию, которая облегчит все вышеперечисленные «патчи». Затем вы можете использовать методы построения графиков R или, возможно, лучше, Klimt (непосредственно из R) для отображения отдельных деревьев.


40

Я опоздал на четыре года, но если вы действительно хотите придерживаться randomForestпакета (и для этого есть веские причины) и хотите реально визуализировать дерево, вы можете использовать пакет reprtree .

Пакет не очень хорошо документирован (вы можете найти документы здесь ), но все довольно просто. Чтобы установить пакет, обратитесь к initialize.R в репозитории, поэтому просто выполните следующее:

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

Затем сделайте свою модель и дерево:

library(randomForest)
library(reprtree)

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

reprtree:::plot.getTree(model)

И вот, пожалуйста! Красиво и просто.

дерево, созданное из plot.getTree (модель)

Вы можете проверить репозиторий github, чтобы узнать о других методах в пакете. На самом деле, если вы проверяете plot.getTree.R , вы заметите, что автор использует свою собственную реализацию, из as.tree()которой chl ♦ предложил вам построить себя в его ответе. Это означает, что вы можете сделать это:

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

И затем потенциально использовать realtreeс другими пакетами построения дерева, такими как дерево .


Большое спасибо, я все еще с радостью принимаю ответы, это, кажется, область, где люди недовольны предложениями. Я думаю, что новая новинка тоже будет поддерживать xgboost.
smci

6
без проблем. Мне потребовались часы, чтобы найти библиотеку / пакет, поэтому я подумал, что если это не будет полезно для вас, это будет для других людей, пытающихся рисовать деревья, но при этом придерживаться randomForestпакета.
Jgozal

2
Классная находка. Примечание: на нем изображено репрезентативное дерево, в некотором смысле дерево в ансамбле, которое в среднем «ближе всего» ко всем остальным деревьям в ансамбле
Крис

2
@Chris Функция plot.getTree()строит отдельное дерево. Функция plot.reprtree()в этом пакете строит репрезентативное дерево.
Чунь Ли

1
Я получил модель из каретки и хочу передать в reptree reprtree:::plot.getTree(mod_rf_1$finalModel), однако есть ошибка "data.frame (var = fr $ var, splits = as.character (gTree [," split point "]),: аргументы подразумевают разные количество строк: 2631, 0 "
HappyCoding

15

Я создал несколько функций для извлечения правил из дерева.

#**************************
#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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.