【问题标题】:MLR3 average scores from an ensemble合奏的 MLR3 平均分数
【发布时间】:2020-09-27 10:34:55
【问题描述】:

使用非常有用的mlr3 book 中的示例,我试图简单地返回堆叠模型输出的平均分数。有人可以解释一下如何使用 mlr3 做到这一点吗?我试过同时使用 LearnerClassifAvg$new(id = "classif.avg")po("classifavg"),但不确定我是否正确应用了这些,谢谢

示例:

library("magrittr")
library("mlr3learners") # for classif.glmnet

task      = mlr_tasks$get("iris")
train.idx = sample(seq_len(task$nrow), 120)
test.idx  = setdiff(seq_len(task$nrow), train.idx)

rprt = lrn("classif.rpart", predict_type = "prob")
glmn = lrn("classif.glmnet", predict_type = "prob")

#  Create Learner CV Operators
lrn_0 = PipeOpLearnerCV$new(rprt, id = "rpart_cv_1")
lrn_0$param_set$values$maxdepth = 5L
lrn_1 = PipeOpPCA$new(id = "pca1") %>>% PipeOpLearnerCV$new(rprt, id = "rpart_cv_2")
lrn_1$param_set$values$rpart_cv_2.maxdepth = 1L
lrn_2 = PipeOpPCA$new(id = "pca2") %>>% PipeOpLearnerCV$new(glmn)

# Union them with a PipeOpNULL to keep original features
level_0 = gunion(list(lrn_0, lrn_1,lrn_2, PipeOpNOP$new(id = "NOP1")))

# Cbind the output 3 times, train 2 learners but also keep level
# 0 predictions
level_1 = level_0 %>>%
  PipeOpFeatureUnion$new(4) %>>%
  PipeOpCopy$new(3) %>>%
  gunion(list(
    PipeOpLearnerCV$new(rprt, id = "rpart_cv_l1"),
    PipeOpLearnerCV$new(glmn, id = "glmnt_cv_l1"),
    PipeOpNOP$new(id = "NOP_l1")
  ))


level_1$plot(html = FALSE)


level_2  <- level_1 %>>%
  PipeOpFeatureUnion$new(3, id = "u2") %>>%
  LearnerClassifAvg$new( id = "classif.avg")

level_2$plot(html = FALSE)


lrn = GraphLearner$new(level_2)


lrn$
  train(task, train.idx)$
  predict(task, test.idx)$
  score()

## returns: Error: Trying to predict response, but incoming data has no factors

【问题讨论】:

  • 您不仅将预测传递给“classif.avg”,还通过PipeOpNOP 将特征和0 级预测传递给“classif.avg”。它很可能不知道如何平均这种输入。也许将它们传递给超级学习者。这是一个示例:mlr3gallery.mlr-org.com/posts/2020-04-27-tuning-stacking。另外“learner_cv”的输出不能作为“classifavg”的输入,
  • 要查看您输入到“classif.avg”的内容,构造level_2 &lt;- level_1 %&gt;&gt;% PipeOpFeatureUnion$new(3, id = "u2") 并运行level_2$train(task)[[1]]$data()。这不是对“classif.avg”的明智输入,但将其输入给另一个学习者是明智的。
  • 谢谢。查看$data() 是一种有用的技术,可以更好地理解输出。我使用提供的链接中的示例将学习者添加到序列的末尾,效果很好。在没有 NOP 的情况下,如何简单地从混合学习者的水平平均分数(作为使用管道的玩具示例)仍然有点不清楚,但也许这首先是一个有缺陷的想法。再次感谢您的回复和帮助。
  • @missuse 感谢您的有用评论。 po("learner_cv" .. ) 的现成预测只能作为学习者的输入吗?有没有办法将这些预测发送到"classif.avg"
  • @ava 目前我认为它们不能被平均,当尝试错误时显示:错误:预测期间 PipeOp learner_cv 的输出类型与 PipeOp classifavg 的输入类型不兼容

标签: r mlr3


【解决方案1】:

如果我们不将特征传递给classif.avg (PipeOpNOP),我们仍然会遇到同样的错误:

Error: Trying to predict response, but incoming data has no factors
library("magrittr")
library("mlr3learners") # for classif.glmnet
library("mlr3verse") #for LearnerClassifAvg
library("mlr3pipelines") # for pipelines

task      = mlr_tasks$get("iris")
train.idx = sample(seq_len(task$nrow), 120)
test.idx  = setdiff(seq_len(task$nrow), train.idx)

rprt = lrn("classif.rpart", predict_type = "prob")
glmn = lrn("classif.glmnet", predict_type = "prob")

#  Create Learner CV Operators
lrn_0 = PipeOpLearnerCV$new(rprt, id = "rpart_cv_1")
lrn_0$param_set$values$maxdepth = 5L
lrn_1 = PipeOpPCA$new(id = "pca1") %>>% PipeOpLearnerCV$new(rprt, id = "rpart_cv_2")
lrn_1$param_set$values$rpart_cv_2.maxdepth = 1L
lrn_2 = PipeOpPCA$new(id = "pca2") %>>% PipeOpLearnerCV$new(glmn)

# Union them with a PipeOpNULL to keep original features
level_0 = gunion(list(lrn_0, lrn_1,lrn_2, PipeOpNOP$new(id = "NOP1")))

# Cbind the output 3 times, train 2 learners but also keep level
# 0 predictions
level_1 = level_0 %>>%
  PipeOpFeatureUnion$new(4) %>>%
  PipeOpCopy$new(2) %>>%
  gunion(list(
    PipeOpLearnerCV$new(rprt, id = "rpart_cv_l1"),
    PipeOpLearnerCV$new(glmn, id = "glmnt_cv_l1")
    # PipeOpNOP$new(id = "NOP_l1") #leave out features here
  ))


level_2  <- level_1 %>>%
  PipeOpFeatureUnion$new(2, id = "u2") %>>%
  LearnerClassifAvg$new( id = "classif.avg")

level_2$plot(html = FALSE)


lrn = GraphLearner$new(level_2)


lrn$
  train(task, train.idx)$
  predict(task, test.idx)$
  score()
#> INFO  [20:42:55.490] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 2/3) 
#> INFO  [20:42:55.557] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 1/3) 
#> INFO  [20:42:55.591] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 3/3) 
#> INFO  [20:42:55.810] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 3/3) 
#> INFO  [20:42:55.849] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 2/3) 
#> INFO  [20:42:55.901] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 1/3) 
#> INFO  [20:42:56.188] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 3/3) 
#> INFO  [20:42:56.299] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 1/3) 
#> INFO  [20:42:56.374] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 2/3) 
#> INFO  [20:42:56.634] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 1/3) 
#> INFO  [20:42:56.699] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 2/3) 
#> INFO  [20:42:56.765] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 3/3) 
#> INFO  [20:42:57.065] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 2/3) 
#> INFO  [20:42:57.177] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 1/3) 
#> INFO  [20:42:57.308] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 3/3)
#> Error: Trying to predict response, but incoming data has no factors

reprex package (v1.0.0) 于 2021 年 3 月 27 日创建

可以通过设置学习器的正确预测类型来缓解此错误:

lrn_avg <- LearnerClassifAvg$new( id = "classif.avg")
lrn_avg$predict_type ="prob"

在此处查看错误消息:https://github.com/cran/mlr3pipelines/blob/master/R/LearnerAvg.R

if (all(fcts) != (self$predict_type == "response")) {
        stopf("Trying to predict %s, but incoming data has %sfactors", self$predict_type, if (all(fcts)) "only " else "no "

用更简单的集成演示解决方案

library("magrittr")
library("mlr3learners") # for classif.glmnet
#> Lade nötiges Paket: mlr3
library("mlr3verse") #for LearnerClassifAvg
library("mlr3pipelines") # for pipelines

# Define task
task      = mlr_tasks$get("iris")
train.idx = sample(seq_len(task$nrow), 120)
test.idx  = setdiff(seq_len(task$nrow), train.idx)

rprt = lrn("classif.rpart", predict_type = "prob")
glmn = lrn("classif.glmnet", predict_type = "prob")

# Define level 0
level_0 =
  gunion(list(
    PipeOpLearnerCV$new(rprt, id = "rpart_cv_l1"),
    PipeOpLearnerCV$new(glmn, id = "glmnt_cv_l1")
    # PipeOpNOP$new(id = "NOP_l1")
  ))

# Create "averager" learner (and set predict type to "prob")
lrn_avg <- LearnerClassifAvg$new( id = "classif.avg")
lrn_avg$predict_type ="prob"

# Combine level 0 and "averager" learner
level_1  <- level_0 %>>%
  PipeOpFeatureUnion$new(2, id = "u1") %>>%
  lrn_avg

# Show ensemble
level_1$plot(html = FALSE)

# Turn into learner
lrn = GraphLearner$new(level_1)

# Make predictions
set.seed(123)
lrn$
  train(task, train.idx)$
  predict(task, test.idx)$
  score()
#> INFO  [14:32:46.626] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 2/3) 
#> INFO  [14:32:46.692] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 3/3) 
#> INFO  [14:32:46.724] [mlr3]  Applying learner 'classif.rpart' on task 'iris' (iter 1/3) 
#> INFO  [14:32:47.060] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 2/3) 
#> INFO  [14:32:47.136] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 1/3) 
#> INFO  [14:32:47.209] [mlr3]  Applying learner 'classif.glmnet' on task 'iris' (iter 3/3)
#> classif.ce 
#>        0.1

reprex package (v1.0.0) 于 2021 年 3 月 28 日创建

【讨论】:

  • 我建议简化答案,这样它就说明了关于特征联合和学习者分类平均的观点,但没有不必要的集成级别。
  • @missuse 谢谢。我删除了答案中不必要的集成级别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多