Làm thế nào để thực sự vẽ một cây mẫu từ RandomForest :: getTree ()? [đóng cửa]


62

Bất cứ ai cũng có thư viện hoặc đề xuất mã về cách thực sự vẽ một vài cây mẫu từ:

getTree(rfobj, k, labelVar=TRUE)

(Có, tôi biết bạn không cần phải thực hiện thao tác này, RF là hộp đen, v.v. các yếu tố được mã hóa của tôi hoạt động tốt như thế nào, v.v.)


Câu hỏi trước mà không có câu trả lời đàng hoàng:

Tôi thực sự muốn vẽ một cây mẫu . Vì vậy, đừng tranh cãi với tôi về điều đó, đã. Tôi không hỏi về varImpPlot(Lô quan trọng thay đổi) hoặc partialPlothoặc MDSPlot, hoặc các lô khác , tôi đã có chúng, nhưng chúng không thể thay thế để nhìn thấy một cây mẫu. Có tôi có thể kiểm tra trực quan đầu ra của getTree(...,labelVar=TRUE).

(Tôi đoán một plot.rf.tree()đóng góp sẽ rất được đón nhận.)


6
Tôi không thấy cần phải tranh luận trước, đặc biệt nếu bạn đang yêu cầu ai đó tình nguyện giúp bạn; nó không đi qua tốt CV có chính sách nghi thức - bạn có thể muốn đọc Câu hỏi thường gặp của chúng tôi .
gung - Phục hồi Monica

9
@gung: mọi câu hỏi trước đây về chủ đề này đã phân rã thành những người khăng khăng rằng nó không cần thiết, và thực sự là dị giáo, để vẽ một cây mẫu. Đọc những trích dẫn tôi đã đưa ra. Tôi đang tìm một bản phác thảo ở đây về cách viết mã vẽ cây rf.
smci

3
Tôi thấy một số câu trả lời mà người dùng đang cố gắng giúp đỡ & giải quyết câu hỏi, cùng với một số ý kiến ​​đặt câu hỏi về tiền đề của ý tưởng (mà tôi thực sự tin rằng cũng được dự định với tinh thần hữu ích). Chắc chắn có thể thừa nhận rằng một số người sẽ không đồng ý với việc thử nghiệm.
gung - Phục hồi Monica

4
Tôi thấy không có câu trả lời mà bất cứ ai đã từng vẽ một cái cây, trong hơn một năm. Tôi đang tìm kiếm một câu trả lời cụ thể cho câu hỏi cụ thể đó.
smci

1
Có thể vẽ một cây duy nhất được xây dựng với cforest(trong gói tiệc ). Nếu không, bạn sẽ phải chuyển đổi data.frametrả về bởi randomForest::getTreemột treeđối tượng giống như.
chl

Câu trả lời:


44

Giải pháp đầu tiên (và dễ nhất): Nếu bạn không thích sử dụng RF cổ điển, như được triển khai trong Andy Liaw randomForest, bạn có thể thử gói bên cung cấp cách triển khai khác của thuật toán RF ban đầu (sử dụng cây có điều kiện và sơ đồ tổng hợp dựa trên trên đơn vị trọng lượng trung bình). Sau đó, như đã báo cáo trên bài đăng trợ giúp R này , bạn có thể vẽ một thành viên duy nhất trong danh sách các cây. Nó dường như chạy trơn tru, như tôi có thể nói. Dưới đây là một âm mưu của một cây được tạo ra bởi cforest(Species ~ ., data=iris, controls=cforest_control(mtry=2, mincriterion=0)).

nhập mô tả hình ảnh ở đây

Thứ hai (gần như là dễ dàng) Giải pháp: Hầu hết các kỹ thuật cây có trụ sở tại R ( tree, rpart, TWIX, vv) cung cấp một treecấu trúc -like in / vẽ một cái cây duy nhất. Ý tưởng sẽ là chuyển đổi đầu ra của randomForest::getTreemột đối tượng R như vậy, ngay cả khi nó không hợp lý theo quan điểm thống kê. Về cơ bản, thật dễ dàng để truy cập cấu trúc cây từ một treeđối tượng, như hiển thị bên dưới. Xin lưu ý rằng nó sẽ hơi khác nhau tùy thuộc vào loại nhiệm vụ - hồi quy so với phân loại - trong trường hợp sau, nó sẽ thêm xác suất cụ thể của lớp làm cột cuối cùng của obj$frame(đó là 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

Sau đó, có các phương pháp để in đẹp và vẽ các đối tượng đó. Các hàm chính là một tree:::plot.treephương thức chung (tôi đặt một bộ ba :cho phép bạn xem mã trực tiếp trong R) dựa vào tree:::treepl(hiển thị đồ họa) và tree:::treeco(tính toán tọa độ các nút). Các chức năng này mong đợi sự obj$frameđại diện của cây. Các vấn đề tinh tế khác: (1) đối số type = c("proportional", "uniform")trong phương pháp vẽ mặc định tree:::plot.tree, giúp quản lý khoảng cách dọc giữa các nút ( proportionalcó nghĩa là nó tỷ lệ với độ lệch, uniformcó nghĩa là nó đã được sửa); (2) bạn cần bổ sung plot(tr)bằng một cuộc gọi để text(tr)thêm nhãn văn bản vào các nút và phân tách, trong trường hợp này có nghĩa là bạn cũng sẽ phải xem qua tree:::text.tree.

Các getTreephương pháp từ randomForestlợi nhuận một cấu trúc khác nhau, mà được diễn tả trong trợ giúp trực tuyến. Một đầu ra điển hình được hiển thị bên dưới, với các nút đầu cuối được chỉ định bởi statusmã (-1). (Một lần nữa, đầu ra sẽ khác nhau tùy thuộc vào loại nhiệm vụ, nhưng chỉ trên các cột statuspredictioncột.)

> 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

Nếu bạn có thể quản lý để chuyển đổi bảng trên cho một tạo ra bởi tree, có thể bạn sẽ có thể tùy chỉnh tree:::treepl, tree:::treecotree:::text.treeđể phù hợp với nhu cầu của bạn, mặc dù tôi không có một ví dụ của phương pháp này. Cụ thể, bạn có thể muốn thoát khỏi việc sử dụng sai lệch, xác suất của lớp, v.v. không có ý nghĩa trong RF. Tất cả những gì bạn muốn là thiết lập tọa độ nút và chia giá trị. Bạn có thể sử dụng fixInNamespace()cho điều đó, nhưng thành thật mà nói, tôi không chắc đây là con đường đúng đắn.

Giải pháp thứ ba (và chắc chắn thông minh): Viết một as.treehàm trợ giúp thực sự sẽ làm giảm bớt tất cả các "bản vá" ở trên. Sau đó, bạn có thể sử dụng các phương pháp vẽ đồ thị của R hoặc, có lẽ tốt hơn, Klimt (trực tiếp từ R) để hiển thị các cây riêng lẻ.


40

Tôi trễ bốn năm, nhưng nếu bạn thực sự muốn bám vào randomForestgói (và có một số lý do chính đáng để làm như vậy) và muốn thực sự trực quan hóa cây, bạn có thể sử dụng gói reprtree .

Gói này không được ghi chép tốt (bạn có thể tìm thấy các tài liệu ở đây ), nhưng mọi thứ đều khá đơn giản. Để cài đặt gói tham khảo khởi tạo.R trong repo, vì vậy chỉ cần chạy như sau:

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

Sau đó hãy tiếp tục và tạo mô hình và cây của bạn:

library(randomForest)
library(reprtree)

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

reprtree:::plot.getTree(model)

Và ở đó bạn đi! Đẹp và đơn giản.

cây được tạo từ plot.getTree (model)

Bạn có thể kiểm tra repo github để tìm hiểu về các phương thức khác trong gói. Trong thực tế, nếu bạn kiểm tra lô.getTree.R , bạn sẽ nhận thấy rằng tác giả sử dụng triển khai của riêng mình trong as.tree()đó chl ♦ đề nghị bạn có thể tự xây dựng câu trả lời của mình. Điều này có nghĩa là bạn có thể làm điều này:

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

Và sau đó có khả năng sử dụng realtreevới các gói âm mưu cây khác như cây .


Cảm ơn rất nhiều, tôi vẫn vui vẻ chấp nhận câu trả lời, đây dường như là một lĩnh vực mà mọi người không đồng ý với các dịch vụ. Tôi đoán điều mới sẽ là hỗ trợ xgboostquá.
smci

6
không vấn đề gì. Tôi đã mất hàng giờ để tìm thư viện / gói để tôi nhận ra rằng nếu không hữu ích với bạn, nó sẽ là cho những người khác cố gắng vẽ cây trong khi vẫn bám vào randomForestgói.
jgozal

2
Tìm kiếm mát mẻ. Lưu ý: Nó vẽ sơ đồ cây đại diện, theo một cách nào đó, cây trong quần thể trung bình là "gần nhất" với tất cả các cây khác trong đoàn
Chris

2
@Chris Hàm plot.getTree()vẽ một cây riêng lẻ. Hàm plot.reprtree()trong gói đó vẽ một cây đại diện.
Chun Li

1
Tôi đã nhận được mô hình từ caret và muốn đưa vào reptree reprtree:::plot.getTree(mod_rf_1$finalModel), tuy nhiên, có "Lỗi trong data.frame (var = fr $ var, splits = as.character (gTree [," split point "]) ,: các đối số ngụ ý khác nhau số lượng hàng: 2631, 0 "
HappyCoding

15

Tôi đã tạo một số chức năng để trích xuất các quy tắc của cây.

#**************************
#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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.