从随机森林中获取知识

机器算法验证 机器学习 数据挖掘 相互作用 随机森林 大车
2022-03-30 05:00:37

随机森林被认为是黑匣子,但最近我在想从随机森林中可以获得什么知识?

最明显的是变量的重要性,在最简单的变体中,它可以通过计算变量出现的次数来完成。
我想到的第二件事是互动。我认为如果树的数量足够大,那么可以测试成对变量的出现次数(类似于卡方独立性)。第三件事是变量的非线性。我的第一个想法只是查看变量 Vs 分数的图表,但我不确定它是否有意义。

添加了 23.01.2012
动机

我想利用这些知识来改进 logit 模型。我认为(或者至少我希望)有可能找到被忽视的相互作用和非线性。

4个回答

随机森林几乎不是黑匣子。它们基于决策树,很容易解释:

#Setup a binary classification problem
require(randomForest)
data(iris)
set.seed(1)
dat <- iris
dat$Species <- factor(ifelse(dat$Species=='virginica','virginica','other'))
trainrows <- runif(nrow(dat)) > 0.3
train <- dat[trainrows,]
test <- dat[!trainrows,]

#Build a decision tree
require(rpart)
model.rpart <- rpart(Species~., train)

这会产生一个简单的决策树:

> model.rpart
n= 111 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

1) root 111 35 other (0.68468468 0.31531532)  
  2) Petal.Length< 4.95 77  3 other (0.96103896 0.03896104) *
  3) Petal.Length>=4.95 34  2 virginica (0.05882353 0.94117647) *

如果 Petal.Length < 4.95,此树将观察分类为“其他”。如果它大于 4.95,它将观察分类为“处女”。随机森林是许多此类树的简单集合,其中每棵树都在数据的随机子集上进行训练。然后每棵树对每个观察的最终分类“投票”。

model.rf <- randomForest(Species~., train, ntree=25, proximity=TRUE, importance=TRUE, nodesize=5)
> getTree(model.rf, k=1, labelVar=TRUE)
  left daughter right daughter    split var split point status prediction
1             2              3  Petal.Width        1.70      1       <NA>
2             4              5 Petal.Length        4.95      1       <NA>
3             6              7 Petal.Length        4.95      1       <NA>
4             0              0         <NA>        0.00     -1      other
5             0              0         <NA>        0.00     -1  virginica
6             0              0         <NA>        0.00     -1      other
7             0              0         <NA>        0.00     -1  virginica

您甚至可以从 rf 中拉出单个树,并查看它们的结构。格式与模型略有不同rpart,但您可以根据需要检查每棵树,并查看它是如何对数据进行建模的。

此外,没有模型是真正的黑匣子,因为您可以检查数据集中每个变量的预测响应与实际响应。无论您要构建哪种模型,这都是一个好主意:

library(ggplot2)
pSpecies <- predict(model.rf,test,'vote')[,2]
plotData <- lapply(names(test[,1:4]), function(x){
  out <- data.frame(
    var = x,
    type = c(rep('Actual',nrow(test)),rep('Predicted',nrow(test))),
    value = c(test[,x],test[,x]),
    species = c(as.numeric(test$Species)-1,pSpecies)
    )
  out$value <- out$value-min(out$value) #Normalize to [0,1]
  out$value <- out$value/max(out$value)
  out
})
plotData <- do.call(rbind,plotData)
qplot(value, species, data=plotData, facets = type ~ var, geom='smooth', span = 0.5)

阴谋

我已将变量(萼片和花瓣长度和宽度)标准化为 0-1 范围。响应也是 0-1,其中 0 是其他,1 是弗吉尼亚。如您所见,随机森林是一个很好的模型,即使在测试集上也是如此。

此外,随机森林将计算变量重要性的各种度量,这可以提供非常丰富的信息:

> importance(model.rf, type=1)
             MeanDecreaseAccuracy
Sepal.Length           0.28567162
Sepal.Width           -0.08584199
Petal.Length           0.64705819
Petal.Width            0.58176828

此表表示删除每个变量会降低模型准确性的程度。最后,您可以从随机森林模型中制作许多其他图,以查看黑匣子中发生的情况:

plot(model.rf)
plot(margin(model.rf)) 
MDSplot(model.rf, iris$Species, k=5)
plot(outlier(model.rf), type="h", col=c("red", "green", "blue")[as.numeric(dat$Species)])

您可以查看每个函数的帮助文件,以更好地了解它们显示的内容。

前段时间,我不得不证明 RF 模型适合我公司的一些化学家。我花了很多时间尝试不同的可视化技术。在这个过程中,我意外地想到了一些新技术,我将它们放入一个 R 包(forestFloor)中,专门用于随机森林可视化。

经典方法是由以下支持的部分依赖图:Rminer(基于数据的敏感性分析是重新发明的部分依赖),或 randomForest 包中的partialPlot我发现部分依赖包iceBOX是一种发现交互的优雅方式。没有使用edarf 包,但似乎有一些专用于 RF 的精细可视化。ggRandomForest包还包含大量有用的可视化

目前 forestFloor 支持 randomForest 对象(对其他 RF 实现的支持正在开发中)。还可以计算梯度提升树的特征贡献,因为训练后的这些树与随机森林树没有太大区别。因此,forestFloor 将来可以支持 XGBoost。部分依赖图是完全模型不变的。

所有包都具有将模型从特征空间到目标空间的几何映射结构可视化的共同点。正弦曲线 y = sin(x) 将是从 x 到 y 的映射,并且可以在 2D 中绘制。直接绘制 RF 映射通常需要太多维度。相反,可以对整个映射结构进行投影、切片或分解,从而将整个映射结构归结为一系列 2D 边缘图。如果您的 RF 模型仅捕获了主效应并且没有变量之间的相互作用,那么经典的可视化方法就可以了。然后你可以像这样简化你的模型结构y=F(X)f1(x1)+f2(x2)+...+fd(xd). 然后每个变量的每个偏函数可以可视化为正弦曲线。如果您的 RF 模型捕获了相当大的交互,那么问题就更大了。结构的 3D 切片可以可视化两个特征和输出之间的交互。问题是要知道要可视化哪些特征组合(iceBOX确实解决了这个问题)。此外,是否还没有考虑其他潜在交互也不容易判断。

本文中,我使用了一个非常早期版本的 forestFloor 来解释一个非常小的 RF 模型捕获的实际生化关系。在本文中,我们彻底描述了特征贡献的可视化,即随机森林的林地可视化

我已经粘贴了 forestFloor 包中的模拟示例,我在其中展示了如何发现模拟的隐藏函数y=x12+sin(x2π)+2x3x4+噪音

#1 - Regression example:
set.seed(1234)
library(forestFloor)
library(randomForest)

#simulate data y = x1^2+sin(x2*pi)+x3*x4 + noise
obs = 5000 #how many observations/samples
vars = 6   #how many variables/features
#create 6 normal distr. uncorr. variables
X = data.frame(replicate(vars,rnorm(obs)))
#create target by hidden function
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 0.5 * rnorm(obs)) 

#grow a forest
rfo = randomForest(
  X, #features, data.frame or matrix. Recommended to name columns.
  Y, #targets, vector of integers or floats
  keep.inbag = TRUE,  # mandatory,
  importance = TRUE,  # recommended, else ordering by giniImpurity (unstable)
  sampsize = 1500 ,   # optional, reduce tree sizes to compute faster
  ntree = if(interactive()) 500 else 50 #speedup CRAN testing
)

#compute forestFloor object, often only 5-10% time of growing forest
ff = forestFloor(
  rf.fit = rfo,       # mandatory
  X = X,              # mandatory
  calc_np = FALSE,    # TRUE or FALSE both works, makes no difference
  binary_reg = FALSE  # takes no effect here when rfo$type="regression"
)


#plot partial functions of most important variables first
plot(ff,                       # forestFloor object
     plot_seq = 1:6,           # optional sequence of features to plot
     orderByImportance=TRUE    # if TRUE index sequence by importance, else by X column  
)

在此处输入图像描述

#Non interacting features are well displayed, whereas X3 and X4 are not
#by applying color gradient, interactions reveal themself 
#also a k-nearest neighbor fit is applied to evaluate goodness-of-fit
Col=fcol(ff,3,orderByImportance=FALSE) #create color gradient see help(fcol)
plot(ff,col=Col,plot_GOF=TRUE) 

在此处输入图像描述

#feature contributions of X3 and X4 are well explained in the context of X3 and X4
# as GOF R^2>.8


show3d(ff,3:4,col=Col,plot_GOF=TRUE,orderByImportance=FALSE)

在此处输入图像描述 在此处输入图像描述

最后是 J.Friedman 描述的由 A.Liaw 编码的部分依赖图的代码。这对主要效果很好。

par(mfrow=c(2,3))
for(i in 1:6) partialPlot(rfo,X,x.var=names(X)[i])

在此处输入图像描述

为了补充这些优秀的响应,我会提到梯度提升树的使用(例如R 中的 GBM 包)。在 R 中,我更喜欢随机森林,因为与需要插补的 randomForest 相比,允许缺失值。可以使用变量重要性和部分图(如 randomForest 中)来帮助您在 logit 模型中进行特征选择和非线性变换探索。此外,变量交互作用是用弗里德曼的 H 统计量 ( interact.gbm) 解决的,参考给出为J.H. Friedman and B.E. Popescu (2005). “Predictive Learning via Rule Ensembles.” Section 8.1Salford Systems 提供了一个名为 TreeNet 的商业版本,该视频演示讲述了他们对可变交互估计视频的看法。

迟到的答案,但我遇到了一个最近的 R 包forestFloor(2015),它可以帮助你以自动化的方式完成这个“取消黑盒”任务。看起来很有前途!

library(forestFloor)
library(randomForest)
#simulate data
obs=1000
vars = 18
X = data.frame(replicate(vars,rnorm(obs)))
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 1 * rnorm(obs))
#grow a forest, remeber to include inbag
rfo=randomForest(X,Y,keep.inbag = TRUE,sampsize=250,ntree=50)
#compute topology
ff = forestFloor(rfo,X)
#ggPlotForestFloor(ff,1:9)
plot(ff,1:9,col=fcol(ff))

产生以下图:

在此处输入图像描述

如果您正在寻找交互,它还提供 3D 可视化。