在 R 中使用纯 Ranger 包进行超参数调整
Hyper-parameter tuning using pure ranger package in R
喜欢用于随机森林模型创建的 ranger 包的速度,但看不到如何调整 mtry 或树的数量。我意识到我可以通过 caret 的 train() 语法来做到这一点,但我更喜欢使用纯 ranger 带来的速度提升。
这是我使用 ranger 创建基本模型的示例(效果很好):
library(ranger)
data(iris)
fit.rf = ranger(
Species ~ .,
training_data = iris,
num.trees = 200
)
print(fit.rf)
查看有关调整选项的官方文档,似乎 csrf() 函数可以提供调整超参数的能力,但我无法正确理解语法:
library(ranger)
data(iris)
fit.rf.tune = csrf(
Species ~ .,
training_data = iris,
params1 = list(num.trees = 25, mtry=4),
params2 = list(num.trees = 50, mtry=4)
)
print(fit.rf.tune)
结果:
Error in ranger(Species ~ ., training_data = iris, num.trees = 200) :
unused argument (training_data = iris)
而且我更愿意使用 ranger 提供的常规(读取:非 csrf)射频算法进行调谐。关于 Ranger 中任一路径的超参数调整解决方案的任何想法?谢谢!
我认为至少有两个错误:
首先,函数ranger
没有参数training_data
。您的错误消息 Error in ranger(Species ~ ., training_data = iris, num.trees = 200) : unused argument (training_data = iris)
指的是那个。当您查看 ?ranger
或 args(ranger)
.
时,您可以看到
其次,另一方面,函数 csrf
具有 training_data
作为输入,但也需要 test_data
。最重要的是,这两个参数没有任何默认值,这意味着您必须提供它们。以下工作没有问题:
fit.rf = ranger(
Species ~ ., data = iris,
num.trees = 200
)
fit.rf.tune = csrf(
Species ~ .,
training_data = iris,
test_data = iris,
params1 = list(num.trees = 25, mtry=4),
params2 = list(num.trees = 50, mtry=4)
)
在这里,我刚刚提供了 iris
作为训练和测试数据集。您显然不想在实际应用程序中这样做。此外,请注意 ranger
也将 num.trees
和 mtry
作为输入,因此您可以尝试在那里调整它。
为了回答我的(不清楚的)问题,显然 ranger 没有内置 CV/GridSearch 功能。然而,这里是你如何在 caret 之外使用 ranger(通过网格搜索)进行超参数调整。感谢 Marvin Wright(Ranger 的维护者)提供的代码。原来带有 ranger 的插入符 CV 对我来说很慢,因为我使用的是公式界面(应该避免)。
ptm <- proc.time()
library(ranger)
library(mlr)
# Define task and learner
task <- makeClassifTask(id = "iris",
data = iris,
target = "Species")
learner <- makeLearner("classif.ranger")
# Choose resampling strategy and define grid
rdesc <- makeResampleDesc("CV", iters = 5)
ps <- makeParamSet(makeIntegerParam("mtry", 3, 4),
makeDiscreteParam("num.trees", 200))
# Tune
res = tuneParams(learner, task, rdesc, par.set = ps,
control = makeTuneControlGrid())
# Train on entire dataset (using best hyperparameters)
lrn = setHyperPars(makeLearner("classif.ranger"), par.vals = res$x)
m = train(lrn, iris.task)
print(m)
print(proc.time() - ptm) # ~6 seconds
出于好奇,相当于插入符号的是
ptm <- proc.time()
library(caret)
data(iris)
grid <- expand.grid(mtry = c(3,4))
fitControl <- trainControl(method = "CV",
number = 5,
verboseIter = TRUE)
fit = train(
x = iris[ , names(iris) != 'Species'],
y = iris[ , names(iris) == 'Species'],
method = 'ranger',
num.trees = 200,
tuneGrid = grid,
trControl = fitControl
)
print(fit)
print(proc.time() - ptm) # ~2.4 seconds
总的来说,如果使用非公式界面,插入符号是使用 ranger 进行网格搜索的最快方法。
请注意,mlr
默认情况下会禁用 ranger 的内部并行化。将超参数 num.threads
设置为可用于加速 mlr
的内核数:
learner <- makeLearner("classif.ranger", num.threads = 4)
或者,通过
启动并行后端
parallelStartMulticore(4) # linux/osx
parallelStartSocket(4) # windows
在调用 tuneParams
并行调整之前。
另一种调整模型的方法是创建手动网格,也许有更好的方法来训练模型,但这可能是一个不同的选择。
hyper_grid <- expand.grid(
mtry = 1:4,
node_size = 1:3,
num.trees = seq(50,500,50),
OOB_RMSE = 0
)
system.time(
for(i in 1:nrow(hyper_grid)) {
# train model
rf <- ranger(
formula = Species ~ .,
data = iris,
num.trees = hyper_grid$num.trees[i],
mtry = hyper_grid$mtry[i],
min.node.size = hyper_grid$node_size[i],
importance = 'impurity')
# add OOB error to grid
hyper_grid$OOB_RMSE[i] <- sqrt(rf$prediction.error)
})
user system elapsed
3.17 0.19 1.36
nrow(hyper_grid) # 120 models
position = which.min(hyper_grid$OOB_RMSE)
head(hyper_grid[order(hyper_grid$OOB_RMSE),],5)
mtry node_size num.trees OOB_RMSE
6 2 2 50 0.1825741858
23 3 3 100 0.1825741858
3 3 1 50 0.2000000000
11 3 3 50 0.2000000000
14 2 1 100 0.2000000000
# fit best model
rf.model <- ranger(Species ~ .,data = iris, num.trees = hyper_grid$num.trees[position], importance = 'impurity', probability = FALSE, min.node.size = hyper_grid$node_size[position], mtry = hyper_grid$mtry[position])
rf.model
Ranger result
Call:
ranger(Species ~ ., data = iris, num.trees = hyper_grid$num.trees[position], importance = "impurity", probability = FALSE, min.node.size = hyper_grid$node_size[position], mtry = hyper_grid$mtry[position])
Type: Classification
Number of trees: 50
Sample size: 150
Number of independent variables: 4
Mtry: 2
Target node size: 2
Variable importance mode: impurity
Splitrule: gini
OOB prediction error: 5.33 %
希望对你有用。
还有 tuneRanger R 包,它是专门为调整 ranger 设计的,使用预定义的调整参数、超参数空间和使用 out-of-bag 观察的智能调整。
请注意,随机森林不是一种算法,通常情况下,调整会产生很大的不同。但它通常可以提高一点性能。
喜欢用于随机森林模型创建的 ranger 包的速度,但看不到如何调整 mtry 或树的数量。我意识到我可以通过 caret 的 train() 语法来做到这一点,但我更喜欢使用纯 ranger 带来的速度提升。
这是我使用 ranger 创建基本模型的示例(效果很好):
library(ranger)
data(iris)
fit.rf = ranger(
Species ~ .,
training_data = iris,
num.trees = 200
)
print(fit.rf)
查看有关调整选项的官方文档,似乎 csrf() 函数可以提供调整超参数的能力,但我无法正确理解语法:
library(ranger)
data(iris)
fit.rf.tune = csrf(
Species ~ .,
training_data = iris,
params1 = list(num.trees = 25, mtry=4),
params2 = list(num.trees = 50, mtry=4)
)
print(fit.rf.tune)
结果:
Error in ranger(Species ~ ., training_data = iris, num.trees = 200) :
unused argument (training_data = iris)
而且我更愿意使用 ranger 提供的常规(读取:非 csrf)射频算法进行调谐。关于 Ranger 中任一路径的超参数调整解决方案的任何想法?谢谢!
我认为至少有两个错误:
首先,函数ranger
没有参数training_data
。您的错误消息 Error in ranger(Species ~ ., training_data = iris, num.trees = 200) : unused argument (training_data = iris)
指的是那个。当您查看 ?ranger
或 args(ranger)
.
其次,另一方面,函数 csrf
具有 training_data
作为输入,但也需要 test_data
。最重要的是,这两个参数没有任何默认值,这意味着您必须提供它们。以下工作没有问题:
fit.rf = ranger(
Species ~ ., data = iris,
num.trees = 200
)
fit.rf.tune = csrf(
Species ~ .,
training_data = iris,
test_data = iris,
params1 = list(num.trees = 25, mtry=4),
params2 = list(num.trees = 50, mtry=4)
)
在这里,我刚刚提供了 iris
作为训练和测试数据集。您显然不想在实际应用程序中这样做。此外,请注意 ranger
也将 num.trees
和 mtry
作为输入,因此您可以尝试在那里调整它。
为了回答我的(不清楚的)问题,显然 ranger 没有内置 CV/GridSearch 功能。然而,这里是你如何在 caret 之外使用 ranger(通过网格搜索)进行超参数调整。感谢 Marvin Wright(Ranger 的维护者)提供的代码。原来带有 ranger 的插入符 CV 对我来说很慢,因为我使用的是公式界面(应该避免)。
ptm <- proc.time()
library(ranger)
library(mlr)
# Define task and learner
task <- makeClassifTask(id = "iris",
data = iris,
target = "Species")
learner <- makeLearner("classif.ranger")
# Choose resampling strategy and define grid
rdesc <- makeResampleDesc("CV", iters = 5)
ps <- makeParamSet(makeIntegerParam("mtry", 3, 4),
makeDiscreteParam("num.trees", 200))
# Tune
res = tuneParams(learner, task, rdesc, par.set = ps,
control = makeTuneControlGrid())
# Train on entire dataset (using best hyperparameters)
lrn = setHyperPars(makeLearner("classif.ranger"), par.vals = res$x)
m = train(lrn, iris.task)
print(m)
print(proc.time() - ptm) # ~6 seconds
出于好奇,相当于插入符号的是
ptm <- proc.time()
library(caret)
data(iris)
grid <- expand.grid(mtry = c(3,4))
fitControl <- trainControl(method = "CV",
number = 5,
verboseIter = TRUE)
fit = train(
x = iris[ , names(iris) != 'Species'],
y = iris[ , names(iris) == 'Species'],
method = 'ranger',
num.trees = 200,
tuneGrid = grid,
trControl = fitControl
)
print(fit)
print(proc.time() - ptm) # ~2.4 seconds
总的来说,如果使用非公式界面,插入符号是使用 ranger 进行网格搜索的最快方法。
请注意,mlr
默认情况下会禁用 ranger 的内部并行化。将超参数 num.threads
设置为可用于加速 mlr
的内核数:
learner <- makeLearner("classif.ranger", num.threads = 4)
或者,通过
启动并行后端parallelStartMulticore(4) # linux/osx
parallelStartSocket(4) # windows
在调用 tuneParams
并行调整之前。
另一种调整模型的方法是创建手动网格,也许有更好的方法来训练模型,但这可能是一个不同的选择。
hyper_grid <- expand.grid(
mtry = 1:4,
node_size = 1:3,
num.trees = seq(50,500,50),
OOB_RMSE = 0
)
system.time(
for(i in 1:nrow(hyper_grid)) {
# train model
rf <- ranger(
formula = Species ~ .,
data = iris,
num.trees = hyper_grid$num.trees[i],
mtry = hyper_grid$mtry[i],
min.node.size = hyper_grid$node_size[i],
importance = 'impurity')
# add OOB error to grid
hyper_grid$OOB_RMSE[i] <- sqrt(rf$prediction.error)
})
user system elapsed
3.17 0.19 1.36
nrow(hyper_grid) # 120 models
position = which.min(hyper_grid$OOB_RMSE)
head(hyper_grid[order(hyper_grid$OOB_RMSE),],5)
mtry node_size num.trees OOB_RMSE
6 2 2 50 0.1825741858
23 3 3 100 0.1825741858
3 3 1 50 0.2000000000
11 3 3 50 0.2000000000
14 2 1 100 0.2000000000
# fit best model
rf.model <- ranger(Species ~ .,data = iris, num.trees = hyper_grid$num.trees[position], importance = 'impurity', probability = FALSE, min.node.size = hyper_grid$node_size[position], mtry = hyper_grid$mtry[position])
rf.model
Ranger result
Call:
ranger(Species ~ ., data = iris, num.trees = hyper_grid$num.trees[position], importance = "impurity", probability = FALSE, min.node.size = hyper_grid$node_size[position], mtry = hyper_grid$mtry[position])
Type: Classification
Number of trees: 50
Sample size: 150
Number of independent variables: 4
Mtry: 2
Target node size: 2
Variable importance mode: impurity
Splitrule: gini
OOB prediction error: 5.33 %
希望对你有用。
还有 tuneRanger R 包,它是专门为调整 ranger 设计的,使用预定义的调整参数、超参数空间和使用 out-of-bag 观察的智能调整。
请注意,随机森林不是一种算法,通常情况下,调整会产生很大的不同。但它通常可以提高一点性能。