关于随机森林的文章,在互联网上铺天盖地,要么是一个简单的介绍,要么是各种抄来的代码。鲜有几篇很地道的文章介绍,也被淹没在了各种搜索排名中,本文利用R的caret包带大家完整做一次真正的“调参侠”,为后面深入理解随机森林做一个很好的示范。

首先,还是引用大家最常用的数据集iris。

library(caret)

# 此处我们按照70%,30%从总样本中随机抽样构成训练和测试集数据
data <- iris
set.seed(2019.1314)
train_data <- data[sample(1:150, 105),]
# 查看数据集
summary(train_data)
qplot(Petal.Length,Petal.Width,colour=Species,data=train_data)
# !!!此处也可以将数据集7:3分取训练集的补集
test_data <- data[sample(1:150, 45),]

接下来就是建模前调参,选优:


# 定义一个5折交叉验证
# 定义模型训练参数,method确定多次交叉检验的抽样方法,number确定了划分的重数
trControl <- trainControl(method = "cv",
    number = 5,
    search = "grid")

# 调参
# 选最优mtry(每棵树使用的特征个数,指定节点中用于树的变量个数,默认情况下数据集变量个数的二次方根(分类模型)或三分之一(预测模型))
set.seed(2020.1314)
# 我们从1尝试到20
tuneGrid <- expand.grid(.mtry = c(1: 20))

rf_mtry <- train(Species~.,
    data = train_data,
    method = "rf",        # 可以用names(getModelInfo())查看所有可用方法
    metric = "Accuracy",  # 评估模型好坏的指标,这里我们用准确率评价
    tuneGrid = tuneGrid,
    trControl = trControl,
    importance = TRUE,
    ntree = 100)

print(rf_mtry)

# 最佳mtry=1
best_mtry <- rf_mtry$bestTune$mtry


# 选最佳maxnodes值(指定树节点的最大个数)
store_maxnode <- list()
tuneGrid <- expand.grid(.mtry = best_mtry)
for (maxnodes in c(2: 20)) {
    set.seed(2020.1314)
    rf_maxnode <- train(Species~.,
        data = train_data,
        method = "rf",
        metric = "Accuracy",
        tuneGrid = tuneGrid,
        trControl = trControl,
        importance = TRUE,
        maxnodes = maxnodes,
        ntree = 300)
    current_iteration <- toString(maxnodes)
    store_maxnode[[current_iteration]] <- rf_maxnode
}
# 最佳maxnodes=10
results_maxnode <- resamples(store_maxnode)
summary(results_maxnode)


# 选最佳nodesize值(指定树节点的最小个数,默认情况下,判别模型为1,回归模型为5;)
store_nodesize <- list()
tuneGrid <- expand.grid(.mtry = best_mtry)
for (nodesize in c(2: 20)) {
    set.seed(2020.1314)
    rf_nodesize <- train(Species~.,
        data = train_data,
        method = "rf",
        metric = "Accuracy",
        tuneGrid = tuneGrid,
        trControl = trControl,
        importance = TRUE,
        maxnodes = 10,
        nodesize = nodesize,
        ntree = 300)
    current_iteration <- toString(nodesize)
    store_nodesize[[current_iteration]] <- rf_nodesize
}
# 最佳nodesize=2
results_nodesize <- resamples(store_nodesize)
summary(results_nodesize)


# 寻找最佳ntree(在森林中树的个数,默认是500)
store_maxtrees <- list()
for (ntree in c(100, 250, 300, 350, 400, 450, 500, 550, 600, 800, 1000, 2000, 3000)) {
    set.seed(2020.1315)
    rf_maxtrees <- train(Species~.,
        data = train_data,
        method = "rf",
        metric = "Accuracy",
        tuneGrid = tuneGrid,
        trControl = trControl,
        importance = TRUE,
        maxnodes = 10,
        ntree = ntree)
    key <- toString(ntree)
    store_maxtrees[[key]] <- rf_maxtrees
}
results_tree <- resamples(store_maxtrees)
# 此处300就已经有很好的准确率,可能现实中我们处理的数据要复杂的多
summary(results_tree)

选好参数后,我们下面进行建模:

# 用选好的参数建模
tuneGrid <- expand.grid(.mtry = best_mtry)
fit_rf <- train(Species~.,
    train_data,
    method = "rf",
    metric = "Accuracy",
    tuneGrid = tuneGrid,
    trControl = trControl,
    importance = TRUE,
    ntree = 300, # 在森林中树的个数
    nodesize = 2,
    maxnodes = 5)
# 查看各个特征的重要程度
varImp(fit_rf)
# 对测试数据进行预测
# 最终能得到97.78%的准确率
prediction <-predict(fit_rf, test_data)
# 计算混淆矩阵
confusionMatrix(prediction, test_data$Species)

最终我们的演示数据能达到97.78%的准确率,但在现实的建模过程中,除了追求其较高的准确率外,还需要关注:

1.防止数据过拟合;

2.生物学意义或者现实应用

总之,机器学习只是一个数据探索的工具,不能一味的依靠它。

参考文章:

1.http://topepo.github.io/caret/index.html