使用bit.names和bits.to.features参数使makeFeatSelWrapper(mlr)对功能组进行包装选择

时间:2018-10-25 09:59:09

标签: r feature-selection mlr

我想使用mlr包通过虹膜数据集的包装方法执行特征选择,但是我只想查看与Petal和/或Sepal相关的特征组。因此,包装程序不会查看不同组合中的四个特征,而是会查看不同组合中的两组特征。

mlr文档指出,可以使用两个参数bit.namesbit.to.feature来执行此操作:

  

bit.names [字符]编码解决方案的位的名称。也   定义编码中的总位数。默认情况下,这些   是任务的功能名称。

     

bits.to.features [function(x,task)]转换   将0-1整数向量转换为选定特征的字符向量。每   默认情况下,第ith位的值为1选择第i个特征   候选解决方案。

我在mlr教程或其他地方找不到使用这两个参数的任何示例。

我将使用?mlr::selectFeatures中提供的示例。

首先使用所有功能

library(mlr)
rdesc <- makeResampleDesc("Holdout")
ctrl <- makeFeatSelControlSequential(method = "sfs",
                                    maxit = NA)
res <- selectFeatures("classif.rpart",
                     iris.task,
                     rdesc,
                     control = ctrl)
analyzeFeatSelResult(res)

这按预期工作

为了遍历要素组,我设计了一个0/1矩阵将要素映射到组(我不确定这是否可行,这似乎很合逻辑):

mati <- rbind(
  c(0,0,1,1),
  c(1,1,0,0))

rownames(mati) <- c("Petal", "Sepal")
colnames(mati) <- getTaskFeatureNames(iris.task)

矩阵如下:

      Sepal.Length Sepal.Width Petal.Length Petal.Width
Petal            0           0            1           1
Sepal            1           1            0           0

现在我运行:

res <- selectFeatures("classif.rpart",
                     iris.task,
                     rdesc,
                     control = ctrl,
                     bit.names = c("Petal", "Sepal"),
                     bits.to.features = function(x = mati, task) mlr:::binaryToFeatures(x, getTaskFeatureNames(task)))

analyzeFeatSelResult(res)
#output
Features         : 1
Performance      : mmce.test.mean=0.0200000
Sepal

Path to optimum:
- Features:    0  Init   :                       Perf = 0.66  Diff: NA  *
- Features:    1  Add    : Sepal                 Perf = 0.02  Diff: 0.64  *

Stopped, because no improving feature was found.

这似乎可以执行我需要的操作,但是我不确定我是否正确定义了bits.to.features参数。

但是当我尝试在包装器中使用相同的方法时:

outer <- makeResampleDesc("CV", iters = 2L)
inner <- makeResampleDesc("Holdout")
ctrl <- makeFeatSelControlSequential(method = "sfs",
                                     maxit = NA)


lrn <- makeFeatSelWrapper("classif.rpart",
                          resampling = inner,
                          control = ctrl,
                          bit.names = c("Petal", "Sepal"),
                          bits.to.features = function(x = mati, task) mlr:::binaryToFeatures(x, getTaskFeatureNames(task)))


r <- resample(lrn, iris.task, outer, extract = getFeatSelResult)

我收到一个错误:

Resampling: cross-validation
Measures:             mmce      
[FeatSel] Started selecting features for learner 'classif.rpart'
With control class: FeatSelControlSequential
Imputation value: 1
[FeatSel-x] 1: 00 (0 bits)
[FeatSel-y] 1: mmce.test.mean=0.7200000; time: 0.0 min
[FeatSel-x] 2: 10 (1 bits)
[FeatSel-y] 2: mmce.test.mean=0.0800000; time: 0.0 min
[FeatSel-x] 2: 01 (1 bits)
[FeatSel-y] 2: mmce.test.mean=0.0000000; time: 0.0 min
[FeatSel-x] 3: 11 (2 bits)
[FeatSel-y] 3: mmce.test.mean=0.0800000; time: 0.0 min
[FeatSel] Result: Sepal (1 bits)
Error in `[.data.frame`(df, , j, drop = drop) : 
  undefined columns selected

我在做什么错了?bit.namesbit.to.feature参数的正确用法是什么?

谢谢

编辑:我在mlr github上发布了一个问题:https://github.com/mlr-org/mlr/issues/2468

1 个答案:

答案 0 :(得分:3)

我猜您发现了两个错误。 第一个是您的代码甚至可以运行,第二个是您的代码无法与嵌套重采样一起使用。

错误1:您的代码不应运行

首先,mati没有任何作用,因为它将被bits.to.features的每次内部调用所覆盖。毕竟,您只是定义了一个默认参数。

您所定义的bit.names "Petal""Sepal"基本上就是告诉mlr使用两位。 因此,特征选择将适用于向量00、01、10、11。 不幸的是,R现在自动将这些向量回收到4的长度,因此10变成1010:

mlr:::binaryToFeatures(c(1,0), getTaskFeatureNames(iris.task))
# [1] "Sepal.Length" "Petal.Length"

我们有我们的第一个错误,即mlr应该避免在这里回收向量。

要使代码按预期运行,您可以这样定义函数bits.to.features

bitnames = c("Sepal", "Petal")
btf = function(x, task) {
  sets = list(
    c("Sepal.Length", "Sepal.Width"), 
    c("Petal.Length", "Petal.Width")
  )
  res = unlist(sets[as.logical(x)])
  if (is.null(res)) {
    return(character(0L))
  } else {
    return(res)  
  }
}

res <- selectFeatures("classif.rpart", iris.task, rdesc, 
  control = ctrl, bits.to.features = btf, bit.names = bitnames)

bts

的说明

引用selectFeatures的帮助页面:

  

[function(x, task)]   将0-1整数向量转换为所选特征的字符向量的函数。   默认情况下,第i位的值为1会选择要在候选解决方案中使用的第i个特征。

因此x是一个包含0和1(例如c(0,0,1,0))的向量。 如果您不更改该功能,它将返回第三个功能的名称(例如,"Petal.Length"用于虹膜)。向量x的长度将始终与定义的bit.names相同。但是,生成的字符向量可以是任何长度。它只需要返回任务的有效功能名称。

在示例中,我将功能名称硬编码到函数bts中。如果要将功能应用于许多不同的任务,则这是一种不好的做法。 因此,mlr使您可以访问task对象,并可以通过getTaskFeatureNames(task)访问功能名称,因此您可以通过编程方式生成功能名称,而无需进行硬编码。

错误2:bit.names必须是功能名称

功能选择将返回结果的位名。然后mlr尝试在数据集中选择这些位名,但显然它们不存在,因为它们完全不相关(在您的情况下)。 现在,该错误已在mlr的github版本中解决。