机器学习--有监督--随机森林

随机森林random forest是一种有监督学习算法,既可用于分类,也能用于回归。本质上使用bagging的思路创建许多决策树,以达到预测目的。

背景知识

1、决策树 decision tree

  • 核心思想:divide-and-conquer 分而治之

简单理解

假设一个训练集(m个样本,n个特征变量,1个响应变量)。而决策树算法是将训练集按照某个特征的某个阈值(yes/no),切割得到两个各自(响应变量)内部相似性很高的子样本集;再对每个子样本集重复上述的步骤(binary recursive partitioning),直至达到预设的条件为止(suitable stopping criterion)


如上有两个注意点:

(1)如何选择针对当前样本集的最佳特征变量的切割阈值

最佳特征变量的切割阈值会将当前样本集切割为两个各自内部响应变量相似度很高的子样本集。针对分类与回归问题,分别有不同的指标。

  • 对于分类问题:具体指标为基尼系数。若子样本集中存在很大部分相同标签(responsible value),则不纯度很低。
    对于预测结果来说:Leaf node样本标签的众数即为预测标签值;其所占的比例就是预测标签的概率值。


注:Pj表示:子样本集中,标签j所占的比例

  • 对于回归问题:具体指标为SSE(误差平方和)。若子样本中的响应变量值基本都在一个确定值范围内波动,则不纯度低。
    对于预测结果来说:Leaf node样本响应变量值的平均数即为预测的值。

注:C1、C2分别表示分得的子样本集响应变量的均值

(2)所谓达到预设的条件的意思

如上所说,并且结合下图,可以总结:训练一棵树就是将Root node(训练数据集)根据选择的切割指标最终得到许多个Leaf node(最终子数据集)的过程。



但如果进行无限的binary recursive partitioning,最终m个样本的数据集会得到m个节点(terminal node)。这样决策树很有可能会过拟合。可通过以下3种方法进行限制

  • ① 直接限定决策树的深度,而深度的定义为:terminal node到root node的最长距离(所经历的决策次数)
  • ② 限制terminal node的size,即terminal node至少要含有指定数目的样本
  • ③ Pruning 修枝剪叶:先训练得到一个超级复杂的树(指定一个很大的深度),然后进行“修剪”得到一个最佳小树的过程(类比正则化回归)。

2、Bagging (Bootstrap aggregating)

  • (1)核心思想:wisdom of the crowd 群体的智慧
  • (2)简单理解:对于一个训练数据集(m个样本),采用Bootstrap方法进行有放回的抽样,训练得到n个模型(base learner)。综合这n个模型的预测结果进行最终的判断(对于分类问题,取众数; 对于回归问题,取均数),从而避免单个模型的过拟合问题,降低方差,提高预测准确率。
  • (3)关键:由于是有放回的抽样,所以训练n个模型所各自基于的样本是有差别的,因此各个模型是有偏好的,否则多个完全一样的模型的综合结果是没有意义的。

bagging是集成学习的一种,常与决策树搭配,即下面将要学习的随机森林。

随机森林

1、简单理解

在上面了解了决策树与bagging之后,随机森林就十分好理解了。

  • 随机森林简单就是使用Bagging思路,建立许多个决策树(弱相关),根据这些决策树的综合预测结果进行回归或者分类。


  • 随机森林在每次建树之前会经历两次抽样过程。首先是基于样本的抽样(一般有放回);其次是基于特征变量的抽样(随机取部分特征变量)。这样就保证了建立每一棵决策树的数据都有一定程度的差异性,然后综合预测结果会更可靠。
  • 由于随机森林相对来说是一种较为复杂的算法,所以在实际训练过程中有多种超参数可供调整,具体将在代码实操中演示。

2、代码实操

  • 示例数据:房价预测(回归)
ames <- AmesHousing::make_ames()
dim(ames)
## [1] 2930   81
set.seed(123)
library(rsample)
split <- initial_split(ames, prop = 0.7, 
                       strata = "Sale_Price")
ames_train  <- training(split)
# [1] 2049   81
ames_test   <- testing(split)
# [1] 881  81
  • 主要R包
# Modeling packages
library(ranger) # a c++ implementation of random forest
2.1 默认参数训练随机森林
# number of features
n_features <- length(setdiff(names(ames_train), "Sale_Price"))
# train a default random forest model
ames_rf1 <- ranger(
  Sale_Price ~ .,
  data = ames_train,
  mtry = floor(n_features / 3),
  respect.unordered.factors = "order",
  seed = 123)

# get OOB RMSE
default_rmse <- sqrt(ames_rf1$prediction.error)
default_rmse
# [1] 25488.39
  • 关于OOB(Out of bag) RMSE
    随机森林算法的优势之一在于其不需要另外的交叉验证。因为是有放回的抽样,对于一个样本来说,总有一部分决策树(1/e的概率)是没有用到该样本的。所以可用那些决策树构成的森林的预测结果与该样本的真实结果比较,从而计算RMSE
2.2 随机森林的超参数
  • (1)决策树的数量
    建议选择特征变量数目的10倍作为训练决策树的数量;
    当然决策树越多,结果越稳定,但消耗的时间也会更长。
  • (2)特征变量的选择
    对于回归问题:建议取特征变量总数的三分之一;对于分类问题,建议取特征变量总数的平方根。
  • (3)决策树复杂度
    常用的方式是限定terminal node size的样本数量(one for classification and five for regression)
  • (4)样本抽样策略
    首先是否采用有放回的抽样方法,其次抽样的数目占总样本数目的多少

在这四种超参数中,后两种对模型性能的影响其实很小,但也不妨一试。

step1:使用full Cartesian grid searches完全笛卡尔积的方式,寻找最佳超参数组合
# create hyperparameter grid
hyper_grid <- expand.grid(
  mtry = floor(n_features * c(.05, .15, .25, .333, .4)),
  min.node.size = c(1, 3, 5, 10),
  replace = c(TRUE, FALSE),
  sample.fraction = c(.5, .63, .8),
  rmse = NA)

# 共有5*4*2*3=120种组合
dim(hyper_grid)
# [1] 120   5

# execute full cartesian grid search
for(i in seq_len(nrow(hyper_grid))) {
  # fit model for ith hyperparameter combination
  fit <- ranger(
    formula = Sale_Price ~ .,
    data = ames_train,
    num.trees = n_features * 10,
    mtry = hyper_grid$mtry[i],
    min.node.size = hyper_grid$min.node.size[i],
    replace = hyper_grid$replace[i],
    sample.fraction = hyper_grid$sample.fraction[i],
    verbose = FALSE,
    seed = 123,
    respect.unordered.factors = 'order',
  )
  # export OOB error
  hyper_grid$rmse[i] <- sqrt(fit$prediction.error)
}

如下为Top10 超参数组合;其中第6列表示相对于默认超参数模型,该超参数组合模型的RMSE下降的百分比。

hyper_grid %>%
  arrange(rmse) %>%
  mutate(perc_gain = (default_rmse - rmse) / default_rmse * 100) %>%
  head(10)
#     mtry min.node.size replace sample.fraction     rmse perc_gain
# 1    26             1   FALSE             0.8 24713.06  3.041873
# 2    26             3   FALSE             0.8 24847.98  2.512570
# 3    20             3   FALSE             0.8 24917.05  2.241554
# 4    20             1   FALSE             0.8 24929.10  2.194284
# 5    32             5   FALSE             0.8 24940.14  2.150967
# 6    32             1   FALSE             0.8 24978.78  1.999392
# 7    32             3   FALSE             0.8 24990.83  1.952085
# 8    26             5   FALSE             0.8 25004.10  1.900044
# 9    20             5   FALSE             0.8 25028.46  1.804464
# 10   12             1   FALSE             0.8 25029.93  1.798693
step2:采用最佳超参数组合建立随机森林模型
best_grid = hyper_grid %>% arrange(rmse) %>% head(1)
fit <- ranger(
  formula = Sale_Price ~ .,
  data = ames_train,
  num.trees = n_features * 10,
  mtry = best_grid$mtry,
  min.node.size = best_grid$min.node.size,
  replace = best_grid$replace,
  sample.fraction = best_grid$sample.fraction,
  verbose = FALSE,
  seed = 123,
  respect.unordered.factors = 'order')

sqrt(fit$prediction.error)
# [1] 24713.06
step3 测试集的数据预测
pred = predict(fit, ames_test)
ModelMetrics::rmse(ames_test$Sale_Price, pred$predictions)
#  [1] 22258.24
2.3 衡量特征变量重要性
  • 方式1:在建立决策树提到了不纯度的概念。当基于该特征的阈值分割,使得样本在切割前后的总体不纯度下降越高,则表明该特征越重要。
rf_impurity <- ranger(
  formula = Sale_Price ~ .,
  data = ames_train,
  num.trees = 2000,
  mtry = 32,
  min.node.size = 1,
  sample.fraction = .80,
  replace = FALSE,
  importance = "impurity", #基于不纯度计算特征重要性
  respect.unordered.factors = "order",
  verbose = FALSE,
  seed = 123)

vip::vip(rf_impurity, num_features = 15, bar = FALSE)
  • 方式2:在计算随机森林模型的基于OOB的RMSE时,如果某一特征值被随意修改,造成模型的准确率下降很多,则该特征越重要。
rf_permutation <- ranger(
  formula = Sale_Price ~ .,
  data = ames_train,
  num.trees = 2000,
  mtry = 32,
  min.node.size = 1,
  sample.fraction = .80,
  replace = FALSE,
  importance = "permutation",
  respect.unordered.factors = "order",
  verbose = FALSE,
  seed = 123)

vip::vip(rf_permutation, num_features = 15, bar = FALSE)

虽然上述两种衡量方式的结果存在一定差异,但可以看出Top3 important feature还是一致的,说明这三种变量对于房价预测是很重要的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容