随机森林如何对异常值不敏感?

机器算法验证 随机森林 引导程序 异常值 大车
2022-02-04 11:42:47

我读过一些资料,包括这个,随机森林对异常值不敏感(例如,逻辑回归和其他 ML 方法的方式)。

然而,有两条直觉告诉我:

  1. 每当构建决策树时,必须对所有点进行分类。这意味着即使是异常值也会被分类,因此会影响在提升期间选择它们的决策树。

  2. 自举是 RandomForest 如何进行子采样的一部分。自举容易受到异常值的影响。

有什么办法可以调和我对异常值敏感性的直觉与不同意的消息来源?

3个回答

你的直觉是正确的。这个答案只是用一个例子来说明它。

CART/RF 对异常值具有某种鲁棒性确实是一个普遍的误解。

为了说明 RF 对单个异常值的存在缺乏鲁棒性,我们可以(轻轻地)修改 Soren Havelund Welling 上述答案中使用的代码,以表明单个“y”异常值足以完全影响拟合的 RF 模型。例如,如果我们将未污染观测值的平均预测误差计算为异常值与其余数据之间距离的函数,我们可以看到(下图)引入单个异常值(通过替换原始观测值之一) 'y' 空间上的任意值)足以将 RF 模型的预测任意地拉离它们在原始(未受污染的)数据上计算时的值:

 library(forestFloor)
library(randomForest)
library(rgl)
set.seed(1)

X = data.frame(replicate(2,runif(2000)-.5))
y = -sqrt((X[,1])^4+(X[,2])^4)
X[1,]=c(0,0);
y2<-y
rg<-randomForest(X,y)   #RF model fitted without the outlier
outlier<-rel_prediction_error<-rep(NA,10)

for(i in 1:10){
    y2[1]=100*i+2
    rf=randomForest(X,y2)   #RF model fitted with the outlier
    rel_prediction_error[i]<-mean(abs(rf$predict[-1]-y2[-1]))/mean(abs(rg$predict[-1]-y[-1]))
    outlier[i]<-y2[1]
}
plot(outlier,rel_prediction_error,type='l',ylab="Mean prediction error (on the uncontaminated observations) \\\ relative to the fit on clean data",xlab="Distance of the outlier")

在此处输入图像描述

多远?在上面的示例中,单个异常值已经极大地改变了拟合,以至于平均预测误差(在未污染的数据上)现在比在未污染数据上拟合模型时要大1-2 个数量级。

因此,单个异常值不能影响 RF 拟合是不正确的。

此外,正如我在其他地方指出的那样,当可能存在多个异常值时,处理异常值要困难得多(尽管它们不需要数据的大部分即可显示其影响)。当然,受污染的数据可能包含多个异常值;要测量几个离群值对 RF 拟合的影响,请将未污染数据上从 RF 获得的左侧图与通过任意移动 5% 的响应值获得的右侧图进行比较(代码在答案下方) .

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

最后,在回归上下文中,重要的是要指出异常值可以从设计和响应空间中的大量数据中脱颖而出 (1)。在 RF 的特定上下文中,设计异常值会影响超参数的估计。但是,当维度数很大时,第二个效果会更加明显。

我们在这里观察到的是一个更一般结果的特殊情况。基于凸损失函数的多元数据拟合方法对异常值的极端敏感性已被多次重新发现。有关 ML 方法的特定上下文中的说明,请参见 (2)。

编辑。

幸运的是,虽然基本 CART/RF 算法对异常值并不鲁棒,但可以(并且很容易)修改程序以将其鲁棒性赋予“y”-异常值。我现在将关注回归 RF(因为这更具体地说是 OP 问题的对象)。更准确地说,为任意节点编写分裂标准t作为:

s=argmaxs[pLvar(tL(s))+pRvar(tR(s))]

其中是依赖于选择的新兴子节点(的隐式函数), 表示落到左子节点的数据比例,是份额中的数据然后,可以通过将原始定义中使用的方差函数替换为稳健的替代方案来赋予回归树(以及 RF 的)“y”空间稳健性。这本质上是 (4) 中使用的方法,其中方差被一个稳健的 M 尺度估计量所取代。tLtRstLtRspLtLpR=1pLtR

  • (1) 揭露多元异常值和杠杆点。Peter J. Rousseeuw 和 Bert C. van Zomeren 美国统计协会杂志卷。85, No. 411(1990 年 9 月),第 633-639 页
  • (2) 随机分类噪声击败了所有凸潜在助推器。Philip M. Long 和 Rocco A. Servedio (2008)。http://dl.acm.org/citation.cfm?id=1390233
  • (3) C. Becker 和 U. Gather (1999)。多元异常值识别规则的掩蔽分解点。
  • (4) Galimberti, G.、Pillati, M. 和 Soffritti, G. (2007)。基于 M 估计量的稳健回归树。统计学,LXVII,173-190。

    library(forestFloor)
    library(randomForest)
    library(rgl)
    set.seed(1)

    X<-data.frame(replicate(2,runif(2000)-.5))
    y<--sqrt((X[,1])^4+(X[,2])^4)
    Col<-fcol(X,1:2) #make colour pallete by x1 and x2
    #insert outlier2 and colour it black
    y2<-y;Col2<-Col
    y2[1:100]<-rnorm(100,200,1);    #outliers
    Col[1:100]="#000000FF" #black

    #plot training set
    plot3d(X[,1],X[,2],y,col=Col)
    rf=randomForest(X,y)    #RF on clean data
    rg=randomForest(X,y2)   #RF on contaminated data
    vec.plot(rg,X,1:2,col=Col,grid.lines=200)
    mean(abs(rf$predict[-c(1:100)]-y[-c(1:100)]))
    mean(abs(rg$predict[-c(1:100)]-y2[-c(1:100)]))

对异常值具有鲁棒性的不是随机森林算法本身,而是它所基于的基础学习器:决策树决策树将非典型观察结果分离成小叶子(即原始空间的小子空间)。此外,决策树是局部模型。与线性回归不同,其中相同的方程适用于整个空间,一个非常简单的模型局部拟合到每个子空间(即,每个叶子)。

  • 在回归的情况下,它一般是一个非常低阶的回归模型(通常只是叶子中观察值的平均值)。
  • 对于分类,它是多数投票。

因此,例如,对于回归,极值不会影响整个模型,因为它们是局部平均的。所以对其他值的拟合不受影响。

实际上,这种理想的属性会延续到其他树状结构,如树状图。例如,分层聚类长期以来一直用于数据清理,因为它会自动将异常观察结果隔离到小聚类中。参见例如Loureiro 等人。(2004 年)。使用聚类方法检测异常值:数据清洗应用程序

因此,简而言之,RF 从递归分区局部模型拟合继承了其对异常值的不敏感性

请注意,决策树是低偏差但高方差的模型:它们的结构很容易在对训练集进行小的修改(删除或添加一些观察值)时发生变化。但这不应与对异常值的敏感性相混淆,这是另一回事。

异常值 1a:此异常值具有一个或多个极端特征值,并且远离任何其他样本。异常值会像任何其他样本一样影响树的初始分裂,因此没有很大的影响。它将与任何其他样本的接近度很低,并且只会在特征空间的远程部分定义模型结构。在预测过程中,大多数新样本可能与这个异常值不相似,并且很少会出现在同一个终端节点中。此外,决策树将特征视为有序的(排名)。该值小于/等于或大于断点,因此特征值是否为极端异常值无关紧要。

异常值 1b:对于分类,当嵌入到不同类别的许多样本中间时,单个样本可能被视为异常值。我之前描述了默认 RF 模型将如何受到这个奇数类样本的影响,但仅非常接近样本。

离群值2:这个离群值有一个极端的目标值,可能比任何其他值高很多倍,但特征值是正常的。0.631 部分的树将具有此样本的终端节点。模型结构将在靠近异常值的地方受到影响。请注意,模型结构主要平行于特征轴受到影响,因为节点是单变量拆分的。

我包括了 outlier_2 的 RF 回归模拟。1999 个点从一个平滑的圆形结构和​​一个目标值高得多的异常值 (y=2, =0, =0) 中提取。训练集显示在左侧。学习到的 RF 模型结构如右图所示。y=(x14+x24)12x1x2

在此处输入图像描述

library(forestFloor)
library(randomForest)
library(rgl)
set.seed(1)

X = data.frame(replicate(2,runif(2000)-.5))
y = -sqrt((X[,1])^4+(X[,2])^4)^1
Col = fcol(X,1:2) #make colour pallete by x1 and x2
#insert outlier2 and colour it black
X[1,] = c(0,0);y[1]=2 ;Col[1] = "#000000FF" #black

#plot training set
plot3d(X[,1],X[,2],y,col=Col)

rf = randomForest(X,y)
vec.plot(rf,X,1:2,col=Col,grid.lines = 400)

编辑:评论 user603

是的,对于目标规模的极端异常值,应该考虑在运行 RF 之前转换目标规模。我在下面添加了一个用于调整 randomForest 的robustModel()函数。另一种解决方案是在训练之前记录转换。

.
##---code by user603
library(forestFloor)
library(randomForest)
library(rgl)
set.seed(1)

X<-data.frame(replicate(2,runif(2000)-.5))
y<--sqrt((X[,1])^4+(X[,2])^4)
Col<-fcol(X,1:2) #make colour pallete by x1 and x2

#insert outlier2 and colour it black
y2<-y;Col2<-Col
y2[1:100]<-rnorm(100,200,1);    #outliers
Col2[1:100]="#000000FF" #black
##---

#function to make models robust
robustModel = function(model,keep.outliers=TRUE) {
  f = function(X,y,lim=c(0.1,.9),keep.outliers="dummy",...) {
  limits = quantile(y,lim)
  if(keep.outliers) {#keep but reduce outliers
  y[limits[1]>y] = limits[1] #lower limit
  y[limits[2]<y] = limits[2] #upper limit
  } else {#completely remove outliers
    thrashThese = mapply("||",limits[1]>y,limits[2]>y)
    y = y[thrashThese]
    X = X[thrashThese,]
  }
  obj = model(x=X,y=y,...)
  class(obj) = c("robustMod",class(obj))
  return(obj)
  }
  formals(f)$keep.outliers = keep.outliers
  return(f)
}

robustRF = robustModel(randomForest) #make RF robust
rh = robustRF(X,y2,sampsize=250)     #train robustRF
vec.plot(rh,X,1:2,col=Col2)          #plot model surface
mean(abs(rh$predict[-c(1:100)]-y2[-c(1:100)]))

在此处输入图像描述