Як насправді побудувати зразкове дерево з randomForest :: getTree ()? [зачинено]


62

Кожен отримав бібліотечні чи кодові пропозиції щодо того, як насправді побудувати пару зразкових дерев :

getTree(rfobj, k, labelVar=TRUE)

(Так, я знаю, що ви не повинні цього робити оперативно, РФ - це чорна скринька тощо) як добре працюють кодовані фактори тощо)


Попередні запитання без гідної відповіді:

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

(Я думаю, що plot.rf.tree()внесок був би дуже добре сприйнятий.)


6
Я не бачу необхідності бути превентивно аргументованою, особливо якщо ви просите, щоб хтось зголосився допомогти вам; це не трапляється добре. Резюме має етикетну політику - ви можете прочитати наші поширені запитання .
— gung - Відновіть Моніку

9
@gung: кожне попереднє запитання на цю тему занепадало до того, що люди наполягають на тому, що не потрібно було, і справді єретично, будувати зразкове дерево. Прочитайте цитати, які я дав. Я шукаю тут ескіз того, як кодувати побудову графічного дерева.
— smci

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

4
Я бачу нульові відповіді, де хто-небудь коли-небудь насадив дерево, за рік. Я шукаю конкретну відповідь на це конкретне питання.
— smci

1
Можна побудувати одне дерево, побудоване з cforest(у пакеті партії ). В іншому випадку вам доведеться перетворити data.frameповернутий randomForest::getTreeоб'єкт у tree-подібний.
— chl

Відповіді:


44

Перше (і найпростіше) рішення: Якщо ви не прагнете дотримуватися класичної RF, як це реалізовано в Енді Ляу randomForest, ви можете спробувати партійний пакет, який забезпечує іншу реалізацію оригінального алгоритму RF ™ (використання умовних дерев та на основі схеми агрегації на основі на одиницю середньої ваги). Тоді, як повідомляється в цьому довідці про R-довідку , ви зможете побудувати одного члена списку дерев. Наче це працює безперебійно, наскільки я можу сказати. Нижче представлена ​​ділянка одного дерева, породженого 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, або, можливо, краще, Клімт (безпосередньо з R) для відображення окремих дерев.


40

Мені запізнюється чотири роки, але якщо ви дійсно хочете дотримуватися randomForestпакету (і є кілька вагомих причин для цього), і хочете насправді візуалізувати дерево, ви можете скористатись пакетом репрі .

Пакет не дуже добре задокументований (ви можете знайти тут документи ), але все досить просто. Щоб встановити пакет, зверніться до ініціалізації.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 repo, щоб дізнатися про інші способи в упаковці. Насправді, якщо ви перевірите 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
я отримав модель від caret і хочу подати у reptree reprtree:::plot.getTree(mod_rf_1$finalModel), однак, є "Помилка data.frame (var = fr $ var, splits = as.character (gTree [," точка розколу "])): аргументи передбачають різницю кількість рядків: 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.