如何获得J48尺寸和叶子数量

How to get J48 size and number of leaves

如果我通过以下方式构建 J48 树:

library(RWeka)

fit <- J48(Species~., data=iris)

我得到以下结果:

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

我想将 Number of Leaves 放入变量 N(因此 N 将得到 5)并将 Size of the tree 放入 S(因此 S 将得到 9)。

有没有办法直接从 J48 树中获取此信息?

有趣的是,fit 的输出似乎是在 print.Weka_classifier 中的 .jcall 函数中创建的,从 getAnywhere(print.Weka_classifier) 中可以看出。这使得从打印输出中提取值变得更加困难(但并非不可能)。

为了存储这两个值,您可以这样做:

library(RWeka)

fit <- J48(Species~., data=iris)

#store the print output in a
a <- capture.output(fit)

> a
 [1] "J48 pruned tree"                                     "------------------"                                 
 [3] ""                                                    "Petal.Width <= 0.6: setosa (50.0)"                  
 [5] "Petal.Width > 0.6"                                   "|   Petal.Width <= 1.7"                             
 [7] "|   |   Petal.Length <= 4.9: versicolor (48.0/1.0)"  "|   |   Petal.Length > 4.9"                         
 [9] "|   |   |   Petal.Width <= 1.5: virginica (3.0)"     "|   |   |   Petal.Width > 1.5: versicolor (3.0/1.0)"
[11] "|   Petal.Width > 1.7: virginica (46.0/1.0)"         ""                                                   
[13] "Number of Leaves  : \t5"                              ""                                                   
[15] "Size of the tree : \t9"      

# get the output length, so that this can work for a tree
# with any size/number of leaves
out_length = length(a)

# then save the number from the fourth to last element to N
N <- as.numeric(gsub('\D', '', a[out_length - 3]))

#then save the number from second to last element to S
S <- as.numeric(gsub('\D', '', a[out_length - 1]))

就这样了:

> N
[1] 5
> S
[1] 9

正如@LyzandeR 之前指出的那样,直接在 J48 对象上执行此操作并不容易。通常,RWeka 中拟合函数返回的对象通常包含相对较少的 R 侧信息(例如,仅调用和拟合预测)。主要成分通常是对 Weka 构建的 Java 对象的引用,Weka 自己的方法可以通过 .jcall 在 Java 端应用,然后在 R 中返回。

然而,对于 J48 树,很容易将 Java 端的信息转换为标准函数和方法可用的 R 对象。 partykit 包提供了一个强制函数,可以将 J48 树转换为 constparty 对象(在叶子中具有常量拟合的递归分区)。然后可以使用length()width()depth()等方法分别查询节点数、叶子数、树的深度。

library("RWeka")
fit <- J48(Species ~ ., data = iris)
library("partykit")
p <- as.party(fit)
length(p)
## [1] 9
width(p)
## [1] 5
depth(p)
## [1] 4

此外,predict()plot()print() 和许多其他工具都可用于 party 对象。

我建议使用这种方法而不是@LyzandeR 建议的文本解析,因为 as.party 转换不依赖于可能容易出错的文本计算。相反,它在内部调用 Weka 自己的 graph 生成器(通过 .jcall),然后将其解析为 constparty 结构。