OOB 决策函数与 scikit-learn RandomForest 中的预测不匹配

数据挖掘 分类 scikit-学习 随机森林 多类分类
2022-03-14 17:07:52

我正在使用 RandomForest 进行多类分类。我想使用 oob_decision_function 来探索精度/召回率,但我不了解 OOB 结果。

我正在使用 25,000 棵树(n_estimators=25000),可能的类值为 0,1 或 2。

我的结果是(截断到前 10 行):

y_train = [1 2 1 1 0 0 2 2 2 2]
y_pred  = [2 2 2 1 0 2 2 2 2 2]

oob_decision_function:
[[ 0.25377529  0.28080796  0.46541674]
 [ 0.32162915  0.3250808   0.35329005]
 [ 0.34463485  0.27709584  0.3782693 ]
 [ 0.31091392  0.2982096   0.39087648]
 [ 0.34932553  0.28632762  0.36434685]
 [ 0.31535905  0.19570567  0.48893528]
 [ 0.25472683  0.35845451  0.38681866]
 [ 0.32521156  0.31721116  0.35757728]
 [ 0.30706625  0.32703203  0.36590172]
 [ 0.29785305  0.22490485  0.4772421 ]]

数据集不统一:

class 0:  32% of samples
class 1:  27% of samples
class 2:  41% of samples

预测似乎与决策函数不一致。例如,参见第 4 个样本:预测 (y_pred[3]) 是第 1 类,但 OOB 值为 0.3109(第 0 类)、0.2982(第 1 类)和 0.3908(第 2 类)。为什么预测是 1 类而不是 2 类?我认为在 25,000 棵树之后,预测应该与 OOB 概率密切匹配,还是我没有正确理解 OOB?

几个问题:

  • OOB 值是如何计算的?我认为它是这样的:为 25,000 棵树中的每一棵树创建一个新的袋装训练集。假设一个给定的样本不包括在 6000 棵树中(即袋外)。当样本在袋外时,当前树用于预测该样本的类别。因此,对于我们给定的样本,估计为 6000 次,假设预测是 0 类(1000 次)、1 类(2000 次)和 2 类(3000 次)。因此,OOB 值为 1000/6000(0 类)、2000/6000(1 类)和 3000/6000(2 类)。它是否正确?

  • OOB 值是使用单个树的预测结果计算的(如上所述),但输出预测(即 y_pred)来自最终的树集合它是否正确?

  • 随着树木数量的增加,OOB 值是否应该收敛到交叉验证值?AFAIK k折交叉验证将数据拆分为k个子集,并在每个子集上使用整个森林。

  • 是否应用了某种加权(例如,如果我的数据不是均匀分布的)?

2个回答

从你的例子我明白ypred是随机森林对训练集的预测。如果是这种情况,ypred会给你训练性能,而 oob 值会给你验证性能。因为您过度拟合,所以您的训练预测接近真实值,而您的验证/oob 预测则不然。

装袋时,平均每个袋子包含 2/3 的样本,剩下的 1/3 在 oob 中。当您使用随机森林对训练集进行预测时,对于每个样本,将有大约 17 000 棵(~2/3*25000)棵树已经看到了该数据点,因为它在他们的包中,并且结果在术语上并不可靠泛化的。换句话说,当您在训练集上进行预测时,2/3 的树将为您提供训练预测,而 1/3 (oob) 将为您提供验证预测,因此总体而言就像获得训练性能一样。

回答你的最后四个问题:

  • sklearn 中的随机森林获取每棵树的每个类的概率,然后在所有包中平均它们以获得最终概率。这通常称为“软投票”,“硬投票”是您描述的方法。 见 1.11.2.1。随机森林

  • 我没有在文档中看到它明确说明,但我希望用于进行一般预测(“软投票”)的相同方法将用于获取 oob 值。

  • 是的,交叉验证和 oob 分数应该非常相似,因为两者都使用分类器尚未看到的数据进行预测。

  • 大多数 sklearn 分类器都有一个名为 class_weight 的超参数,当你有不平衡的数据时可以使用它,但默认情况下,在随机森林中,每个样本的权重相同。

来自文档

RandomForestClassifier 使用 bootstrap 聚合进行训练,其中每棵新树都从训练观察的 bootstrap 样本中拟合 z_i = (x_i, y_i)误差是使用不包含 在它们各自的引导样本中的树的预测计算out-of-bag (OOB)的每个计算的平均误差这允许 RandomForestClassifier 在训练时进行拟合和验证。所以在这种情况下,我们实际上不需要验证数据集或 k-foldz_iz_i

(答案并不严格按照您的问题排序)

直观的理解(如果不阅读下面的文档,文档非常清楚..)

假设我们的训练数据集用 T 表示,假设数据集有 M 个特征(或属性或变量)。

T = {(X1,y1), (X2,y2), ... (Xn, yn)} and Xi is input vector {xi1, xi2, ... xiM} and yi is the label (or output or class).

射频摘要:

随机森林算法是一种主要基于两种方法的分类器 - 装袋和随机子空间方法。 

假设我们决定S在我们的森林中拥有许多树,那么我们首先创建 S 个“与原始大小相同”的数据集,这些数据集是T通过替换数据的随机重采样创建的(n每个数据集的时间)。这将产生{T1, T2, ... TS}数据集。这些中的每一个都称为引导数据集。由于“替换”,每个数据集Ti都可能有重复的数据记录,并且 Ti 可能会丢失原始数据集中的多个数据记录。这称为装袋。 

现在,RF创建S树并使用可能特征中m (=sqrt(M) or =floor(lnM+1))的随机子M特征来创建任何树。这就是所谓的random subspace method. 

因此,为每个Ti引导数据集创建一棵树Ki如果你想对一些输入数据进行分类D = {x1, x2, ..., xM},你让它通过每棵树并产生S输出(每棵树一个),这可以表示为Y = {y1, y2, ..., ys}.最终预测是对该集合的多数投票。 

袋外错误:

创建分类器后,对于原始训练集中(S trees)的每一个,即选择所有不包括的分类器注意,这个子集是一组自举数据集,不包含原始数据集中的特定记录。这组被称为袋外示例。有 n 个这样的子集(原始数据集 T 中的每个数据记录一个)。(Xi,yi)TTk(Xi,yi)OOB classifier is the aggregation of votes ONLY over Tk such that it does not contain (xi,yi). 

泛化误差的袋外估计是训练集上袋外分类器的错误率(与已知的 yi 进行比较)。

Also your n_estimators is Quite High which will lead you to Overffiting

当我们有严重的不平衡时, RF也不是一个好的选择,因为随机森林是建立在决策树上的,而决策树对类不平衡很敏感。因此,每棵树都会因类别不平衡而偏向相同的方向和幅度(平均而言)。

只是一个旁注,

Bagging 和 Boosting可能听起来很相似,但并不相似。Xgboost 可以处理不平衡,而 RF 则不能。

希望能帮助到你..