Bagaimana cara sebenarnya memplot pohon contoh dari randomForest :: getTree ()? [Tutup]


62

Siapa pun mendapat saran pustaka atau kode tentang cara sebenarnya merencanakan beberapa pohon sampel dari:

getTree(rfobj, k, labelVar=TRUE)

(Ya saya tahu Anda tidak seharusnya melakukan ini secara operasional, RF adalah kotak hitam, dll. Saya ingin secara visual kewarasan-periksa pohon untuk melihat apakah ada variabel yang berperilaku berlawanan, perlu penyesuaian / penggabungan / diskritisasi / transformasi, periksa seberapa baik faktor yang disandikan saya berfungsi, dll.)


Pertanyaan sebelumnya tanpa jawaban yang layak:

Saya sebenarnya ingin memplot pohon contoh . Jadi jangan berdebat dengan saya tentang itu, sudah. Saya tidak bertanya tentang varImpPlot(Variable Importance Plot) atau partialPlotatau MDSPlot, atau plot lainnya ini , saya sudah memilikinya, tetapi itu bukan pengganti untuk melihat pohon sampel. Ya saya dapat secara visual memeriksa output getTree(...,labelVar=TRUE).

(Saya kira plot.rf.tree()kontribusi akan diterima dengan sangat baik.)


6
Saya tidak melihat perlunya berdebat terlebih dahulu, terutama jika Anda meminta seseorang untuk secara sukarela membantu Anda; itu tidak menemukan dengan baik. CV memiliki kebijakan etiket - Anda mungkin ingin membaca FAQ kami .
gung - Reinstate Monica

9
@ungung: setiap pertanyaan sebelumnya tentang topik ini telah membusuk ke orang yang bersikeras bahwa itu tidak perlu, dan memang sesat, untuk merencanakan pohon sampel. Baca kutipan yang saya berikan. Saya sedang mencari sketsa di sini tentang bagaimana kode merencanakan pohon rf.
smci

3
Saya melihat beberapa jawaban di mana pengguna mencoba untuk membantu & menjawab pertanyaan, bersama dengan beberapa komentar yang mempertanyakan premis ide (yang, saya percaya, sejujurnya, dimaksudkan dengan semangat membantu juga). Tentu saja mungkin untuk mengakui bahwa beberapa orang tidak akan setuju jika tidak pemalu.
gung - Reinstate Monica

4
Saya melihat nol jawaban di mana ada yang pernah merencanakan pohon, lebih dari setahun. Saya mencari jawaban spesifik untuk pertanyaan spesifik itu.
smci

1
Dimungkinkan untuk memplot satu pohon yang dibangun dengan cforest(dalam paket partai ). Jika tidak, Anda harus mengonversi yang data.framedikembalikan oleh randomForest::getTreeke tree-seperti objek.
chl

Jawaban:


44

Solusi pertama (dan termudah): Jika Anda tidak ingin tetap menggunakan RF klasik, seperti yang diterapkan di Andy Liaw's randomForest, Anda dapat mencoba paket pesta yang menyediakan implementasi berbeda dari algoritma RF asli (penggunaan pohon kondisional dan skema agregasi berdasarkan rata-rata berat unit). Kemudian, seperti yang dilaporkan pada pos bantuan-R ini , Anda dapat memplot satu anggota dari daftar pohon. Sepertinya berjalan lancar, sejauh yang saya tahu. Di bawah ini adalah plot satu pohon yang dihasilkan oleh cforest(Species ~ ., data=iris, controls=cforest_control(mtry=2, mincriterion=0)).

masukkan deskripsi gambar di sini

Kedua (hampir semudah) solusi: Sebagian besar teknik berbasis pohon di R ( tree, rpart, TWIX, dll) menawarkan treestruktur-seperti untuk pencetakan / merencanakan satu pohon. Idenya adalah untuk mengkonversi output randomForest::getTreeke objek R seperti itu, bahkan jika itu tidak masuk akal dari sudut pandang statistik. Pada dasarnya, mudah untuk mengakses struktur pohon dari suatu treeobjek, seperti yang ditunjukkan di bawah ini. Harap dicatat bahwa itu akan sedikit berbeda tergantung pada jenis tugas - regresi vs klasifikasi - di mana dalam kasus selanjutnya akan menambah probabilitas kelas-spesifik sebagai kolom terakhir dari obj$frame(yang merupakan a 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

Lalu, ada metode untuk mencetak dan merencanakan objek-objek itu dengan cantik. Fungsi kuncinya adalah tree:::plot.treemetode generik (saya menempatkan triple :yang memungkinkan Anda untuk melihat kode dalam R langsung) bergantung pada tree:::treepl(tampilan grafis) dan tree:::treeco(menghitung koordinat node). Fungsi-fungsi ini mengharapkan obj$framerepresentasi pohon. Masalah halus lainnya: (1) argumen type = c("proportional", "uniform")dalam metode plotting default tree:::plot.tree,, membantu mengatur jarak vertikal antara node ( proportionalberarti proporsional dengan penyimpangan, uniformberarti tetap); (2) Anda perlu melengkapi plot(tr)dengan panggilan untuk text(tr)menambahkan label teks ke node dan split, yang dalam hal ini berarti Anda juga harus melihat tree:::text.tree.

The getTreemetode dari randomForesthasil struktur yang berbeda, yang didokumentasikan dalam bantuan online. Output khas ditunjukkan di bawah ini, dengan terminal node ditunjukkan oleh statuskode (-1). (Sekali lagi, output akan berbeda tergantung pada jenis tugas, tetapi hanya pada kolom statusdan 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

Jika Anda dapat mengubah tabel di atas menjadi yang dihasilkan oleh tree, Anda mungkin akan dapat menyesuaikan tree:::treepl, tree:::treecodan tree:::text.treesesuai dengan kebutuhan Anda, meskipun saya tidak memiliki contoh pendekatan ini. Secara khusus, Anda mungkin ingin menyingkirkan penggunaan penyimpangan, probabilitas kelas, dll. Yang tidak berarti dalam RF. Yang Anda inginkan adalah mengatur koordinat node dan nilai split. Anda bisa menggunakannya fixInNamespace()untuk itu, tetapi, jujur ​​saja, saya tidak yakin ini cara yang tepat.

Solusi ketiga (dan tentu saja pintar): Tulis as.treefungsi pembantu yang benar yang akan meringankan semua "tambalan" di atas. Anda kemudian dapat menggunakan metode merencanakan R atau, mungkin lebih baik, Klimt (langsung dari R) untuk menampilkan masing-masing pohon.


40

Saya terlambat empat tahun, tetapi jika Anda benar-benar ingin tetap berpegang pada randomForestpaket (dan ada beberapa alasan bagus untuk melakukannya), dan ingin benar-benar memvisualisasikan pohon, Anda dapat menggunakan paket reprtree .

Paket ini tidak didokumentasikan dengan sangat baik (Anda dapat menemukan dokumen di sini ), tetapi semuanya sangat mudah. Untuk menginstal paket merujuk ke initialize.R di repo, jadi jalankan saja yang berikut:

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

Kemudian lanjutkan dan buat model dan pohon Anda:

library(randomForest)
library(reprtree)

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

reprtree:::plot.getTree(model)

Dan begitulah! Cantik dan sederhana.

pohon yang dihasilkan dari plot.getTree (model)

Anda dapat memeriksa repo github untuk mempelajari tentang metode lain dalam paket. Bahkan, jika Anda memeriksa plot.getTree.R , Anda akan melihat bahwa penulis menggunakan implementasinya sendiri as.tree()yang disarankan oleh Chl: Anda bisa membangun diri dalam jawabannya. Ini artinya Anda bisa melakukan ini:

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

Dan kemudian berpotensi digunakan realtreedengan paket plot pohon lain seperti tree .


Terima kasih banyak, saya masih dengan senang hati menerima jawaban, ini tampaknya menjadi area di mana orang tidak setuju dengan penawaran. Saya kira hal baru yang baru akan mendukung xgboostjuga.
smci

6
tidak masalah. Butuh waktu berjam-jam untuk menemukan perpustakaan / paket jadi saya pikir jika tidak berguna bagi Anda, itu akan menjadi orang lain yang mencoba menggambar pohon sambil tetap menempel pada randomForestpaket.
jgozal

2
Temuan keren. Catatan: Ini memplot pohon yang representatif, dalam arti tertentu, pohon dalam ansambel yang rata-rata "paling dekat" dengan semua pohon lain dalam ansambel
Chris

2
@ Chris Fungsi akan plot.getTree()memplot satu pohon individual. Fungsi plot.reprtree()dalam paket itu memplot pohon representatif.
Chun Li

1
saya mendapatkan model dari caret dan ingin memasukkan ke dalam reptree dengan reprtree:::plot.getTree(mod_rf_1$finalModel), bagaimanapun, ada "Kesalahan dalam data.frame (var = fr $ var, splits = as.character (gTree [," split point "]),: argumen menyiratkan perbedaan jumlah baris: 2631, 0 "
HappyCoding

15

Saya telah membuat beberapa fungsi untuk mengekstrak aturan pohon.

#**************************
#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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.