J48 树 (RWeka) 中的属性及其值

Properties and their values out of J48 tree (RWeka)

如果您运行满足以下条件:

library(RWeka) 
data(iris) 
res = J48(Species ~., data = iris)

res 将是 class J48 的列表,继承自 Weka_tree。如果你打印它

R> res
J48 pruned tree
------------------

Petal.Width <= 0.6: setosa (50.0)
Petal.Width > 0.6
|   Petal.Width <= 1.7
|   |   Petal.Length <= 4.9: versicolor (48.0/1.0)
|   |   Petal.Length > 4.9
|   |   |   Petal.Width <= 1.5: virginica (3.0)
|   |   |   Petal.Width > 1.5: versicolor (3.0/1.0)
|   Petal.Width > 1.7: virginica (46.0/1.0)

Number of Leaves  :     5

Size of the tree :  9

我想按从右到左的顺序获取属性及其值。所以对于这种情况:

Petal.Width, Petal.Width, Petal.Length, Petal.Length.

我试图将 res 输入到一个因子并输入 运行 命令:

str_extract(paste0(x, collapse=""), perl("(?<=\|)[A-Za-z]+(?=\|)"))

没有成功。 请记住,我们应该忽略左边的字符。

我希望我没有漏掉你的意思,但我假设你想以某种方式创建和存储基于树模型终端节点的规则。就个人而言,我发现模型树构建包(RWeka、party、partykit、rpart)无法让用户在构建模型后创建有用的规则列表。当然,当你的变量和拆分很少时,你可以解释树图。

到目前为止我发现的(我自己使用的)唯一简单可靠的方法是 rpart 包的命令 "path.rpart"。如果你真的想使用 RWeka,解决方案似乎无关紧要,但我会试一试:

library(rpart)

res = rpart(Species ~., data = iris)

res

# n= 150 
# 
# node), split, n, loss, yval, (yprob)
# * denotes terminal node
# 
# 1) root 150 100 setosa (0.33333333 0.33333333 0.33333333)  
# 2) Petal.Length< 2.45 50   0 setosa (1.00000000 0.00000000 0.00000000) *
#   3) Petal.Length>=2.45 100  50 versicolor (0.00000000 0.50000000 0.50000000)  
# 6) Petal.Width< 1.75 54   5 versicolor (0.00000000 0.90740741 0.09259259) *
#   7) Petal.Width>=1.75 46   1 virginica (0.00000000 0.02173913 0.97826087) *


# capture terminal nodes
terminal_nodes = rownames(res$frame)[res$frame$var =="<leaf>"]

# print rules for the terminal nodes
path.rpart(res ,nodes=terminal_nodes)

# node number: 2 
# root
# Petal.Length< 2.45
# 
# node number: 6 
# root
# Petal.Length>=2.45
# Petal.Width< 1.75
# 
# node number: 7 
# root
# Petal.Length>=2.45
# Petal.Width>=1.75


# print above rules as list
rules = path.rpart(res ,nodes=terminal_nodes)
listed_rules = unlist(rules)
sapply(rules,"[",-1)

# $`2`
# [1] "Petal.Length< 2.45"
# 
# $`6`
# [1] "Petal.Length>=2.45" "Petal.Width< 1.75" 
# 
# $`7`
# [1] "Petal.Length>=2.45" "Petal.Width>=1.75" 

一种方法是将 J48 对象从 RWeka 转换为 party 对象从 partykit。您只需要 as as.party(res),这会为您完成所有解析,returns 一个更易于使用标准化提取函数等的结构。

特别是您可以使用其他关于 ctree 对象等的讨论中给出的所有建议。参见

  • Get decision tree rule/path pattern for every row of predicted dataset for rpart/ctree package in R

而且我认为以下内容至少可以满足您的部分需求:

library("partykit")
pres <- as.party(res)
partykit:::.list.rules.party(pres)
##                                                                                  2 
##                                                               "Petal.Width <= 0.6" 
##                                                                                  5 
##                     "Petal.Width > 0.6 & Petal.Width <= 1.7 & Petal.Length <= 4.9" 
##                                                                                  7 
## "Petal.Width > 0.6 & Petal.Width <= 1.7 & Petal.Length > 4.9 & Petal.Width <= 1.5" 
##                                                                                  8 
##  "Petal.Width > 0.6 & Petal.Width <= 1.7 & Petal.Length > 4.9 & Petal.Width > 1.5" 
##                                                                                  9 
##                                            "Petal.Width > 0.6 & Petal.Width > 1.7" 

更新:OP 在列表外联系了我一个相关问题,要求提供树的特定打印表示。我在这里包括我的解决方案,以防它对其他人有用。

他想要 ( ) 符号表示层次结构级别以及拆分变量的名称。一种方法是 (1) 提取基础数据的变量名称:

nam <- names(pres$data)

(2) 将树的递归节点结构转为扁平列表(这样在构造想要的字符串时更方便一些):

tr <- as.list(pres$node)

(3a) 初始化字符串:

str <- "("

(3b)递归地在字符串中添加括号and/or变量名:

update_str <- function(x) {
   if(is.null(x$kids)) {
     str <<- paste(str, ")")
   } else {
     str <<- paste(str, nam[x$split$varid], "(")
     for(i in x$kids) update_str(tr[[i]])
   }
}

(3c) 调用递归,从根节点开始:

update_str(tr[[1]])
str
## [1] "( Petal.Width ( ) Petal.Width ( Petal.Length ( ) Petal.Width ( ) ) )"